本文来源于:知乎
作者:李嘉琪
Error系列的指标及loss损失函数,该系列有:
均方误差(Mean Square Error,MSE) 平均绝对误差(Mean Absolute Error,MAE) 均方根误差(Root Mean Square Error,RMSE) 均方对数误差(Mean Squared Log Error) 平均相对误差(Mean Relative Error,MAE)
今天为大家打包整理均方误差(Mean Square Error,MSE)、平均绝对误差(Mean Absolute Error,MAE)、均方根误差(Root Mean Square Error,RMSE)的原理介绍及MindSpore的实现代码。
均方误差指的就是模型预测值与样本真实值 y 之间距离平方的平均值。其公式如下所示:
其中,和
分别表示第
个样本的真实值和预测值,
为样本个数。













import numpy as np import matplotlib.pyplot as plt x = np.linspace(1, 20, 40) y = x + [np.random.choice(4) for _ in range(40)] y[-5:] -= 8 X = np.vstack((np.ones_like(x),x)) # 引入常数项 1 m = X.shape[1] # 参数初始化 W = np.zeros((1,2)) # 迭代训练 num_iter = 20 lr = 0.01 J = [] for i in range(num_iter): y_pred = W.dot(X) loss = 1/(2*m) * np.sum((y-y_pred)**2) J.append(loss) W = W + lr * 1/m * (y-y_pred).dot(X.T) # 作图 y1 = W[0,0] + W[0,1]*1 y2 = W[0,0] + W[0,1]*20 plt.scatter(x, y) plt.plot([1,20],[y1,y2]) plt.show()
拟合结果如下图所示:
可见,使用损失函数,受离群点的影响较大,虽然样本中只有 5 个离群点,但是拟合的直线还是比较偏向于离群点。这往往是我们不希望看到的。
Mean Squared Error的Metric代码实现
"""Error.""" import numpy as np from .metric import Metric class MSE(Metric): def __init__(self): super(MSE, self).__init__() self.clear() def clear(self): """清除历史数据""" self._squared_error_sum = 0 self._samples_num = 0 def update(self, *inputs): # 校验输入的个数 if len(inputs) != 2: raise ValueError('Mean squared error need 2 inputs (y_pred, y), but got {}'.format(len(inputs))) # 将输入统一转换为numpy y_pred = self._convert_data(inputs[0]) y = self._convert_data(inputs[1]) # 复现公式 squared_error_sum = np.power(y.reshape(y_pred.shape) - y_pred, 2) # 多组数据进行累加 self._squared_error_sum += squared_error_sum.sum() # 统计数据的个数,方便后面求均值 self._samples_num += y.shape[0] def (self): """ 返回值是一个float的标量。 """ if self._samples_num == 0: raise RuntimeError('The number of input samples must not be 0.') return self._squared_error_sum / self._samples_num
使用方法如下:
import math import numpy as np from mindspore import Tensor from mindspore.nn.metrics import MSE def test_MSE(): x = Tensor(np.array([0.1, 0.2, 0.6, 0.9])) y = Tensor(np.array([0.1, 0.25, 0.5, 0.9])) error = MSE() error.clear() error.update(x, y) result = error.() print() test_MSE() 0.0125 / 4
Mean Squared Error的Loss代码实现
import mindspore import mindspore.common.dtype as mstype from mindspore.common.tensor import Tensor from mindspore.common.parameter import Parameter from mindspore.ops import operations as P from mindspore.ops import functional as F from mindspore import nn class MSELoss(_Loss): def construct(self, base, target): x = F.square(base - target) return self.get_loss(x)
使用方法如下:
import numpy as np from mindspore import nn import mindspore from mindspore import Tensor loss = nn.MSELoss() input_data = Tensor(np.array([1, 2, 3]), mindspore.float32) target_data = Tensor(np.array([1, 2, 2]), mindspore.float32) output = loss(input_data, target_data) print(output) 0.33333334




直观上来看,MAE 的曲线呈 V 字型,连续但在 y-f(x)=0 处不可导,计算机求解导数比较困难。而且 MAE 大部分情况下梯度都是相等的,这意味着即使对于小的损失值,其梯度也是大的。这不利于函数的收敛和模型的学习。
X = np.vstack((np.ones_like(x),x)) # 引常数项 1 m = X.shape[1] # 参数初始化 W = np.zeros((1,2)) # 迭代训练 num_iter = 20 lr = 0.01 J = [] for i in range(num_iter): y_pred = W.dot(X) loss = 1/m * np.sum(np.abs(y-y_pred)) J.append(loss) mask = (y-y_pred).copy() mask[y-y_pred > 0] = 1 mask[mask <= 0] = -1 W = W + lr * 1/m * mask.dot(X.T) # 作图 y1 = W[0,0] + W[0,1]*1 y2 = W[0,0] + W[0,1]*20 plt.scatter(x, y) plt.plot([1,20],[y1,y2],'r--') plt.xlabel('x') plt.ylabel('y') plt.('MAE') plt.show()
注意上述代码中对 MAE 计算梯度的部分。拟合结果如下图所示:
显然,使用 MAE 损失函数,受离群点的影响较小,拟合直线能够较好地表征正常数据的分布情况。这一点,MAE 要优于 MSE。二者的对比图如下:
Mean Absolute Error的Metric代码实现
"""Error.""" import numpy as np from .metric import Metric class MAE(Metric): def __init__(self): super(MAE, self).__init__() self.clear() def clear(self): """清除历史数据""" self._abs_error_sum = 0 self._samples_num = 0 def update(self, *inputs): # 检验输入个数 if len(inputs) != 2: raise ValueError('Mean absolute error need 2 inputs (y_pred, y), but got {}'.format(len(inputs))) y_pred = self._convert_data(inputs[0]) y = self._convert_data(inputs[1]) # 复现公式计算 abs_error_sum = np.abs(y.reshape(y_pred.shape) - y_pred) # 多组数据进行累加 self._abs_error_sum += abs_error_sum.sum() # 统计数据的个数,方便后面求均值 self._samples_num += y.shape[0] def (self): """ 返回值是一个float的标量。 """ if self._samples_num == 0: raise RuntimeError('Total samples num must not be 0.') return self._abs_error_sum / self._samples_num
使用方法如下:
import numpy as np import mindspore from mindspore import Tensor from mindspore.nn.metrics import MAE x = Tensor(np.array([0.1, 0.2, 0.6, 0.9]), mindspore.float32) y = Tensor(np.array([0.1, 0.25, 0.7, 0.9]), mindspore.float32) error = MAE() error.clear() error.update(x, y) result = error.() print(result) 0.037499990314245224
每个batch(比如两组数据)进行计算的时候如下:
import numpy as np from mindspore import Tensor from mindspore.nn.metrics import MAE error = MAE() error.clear() x = Tensor(np.array([0.1, 0.2, 0.6, 0.9])) y = Tensor(np.array([0.1, 0.25, 0.7, 0.9])) error.update(x, y) x1 = Tensor(np.array([0.1, 0.2, 0.6, 0.9])) y1 = Tensor(np.array([0.1, 0.25, 0.7, 0.9])) error.update(x1, y1) result = metric.() print(result) Mean Squared Error的Loss代码实现 import mindspore import mindspore.common.dtype as mstype from mindspore.common.tensor import Tensor from mindspore.common.parameter import Parameter from mindspore.ops import operations as P from mindspore.ops import functional as F from mindspore import nn class MAELoss(_Loss): def construct(self, logits, label): _check_shape(logits.shape, label.shape) x = F.absolute(logits - label) return self.get_loss(x)
使用方法如下:
import numpy as np from mindspore import nn import mindspore from mindspore import Tensor loss = nn.MAELoss() input_data = Tensor(np.array([1, 2, 3]), mindspore.float32) target_data = Tensor(np.array([1, 2, 2]), mindspore.float32) output = loss(input_data, target_data) print(output) 0.33333334





Root Mean Squared Error的Loss代码实现
import mindspore import mindspore.common.dtype as mstype from mindspore.common.tensor import Tensor from mindspore.common.parameter import Parameter from mindspore.ops import operations as P from mindspore.ops import functional as F from mindspore import nn class RMSELoss(_Loss): def __init__(self): super(RMSELoss, self).__init__() # 结果是基于MSE的 self.MSELoss = MSELoss() def construct(self, logits, label): # 校验输入的维度 _check_shape(logits.shape, label.shape) # 基于MSE的结果进行开方 rmse_loss = F.sqrt(self.MSELoss(logits, label)) return rmse_loss
使用方法如下:
import numpy as np from mindspore import nn import mindspore from mindspore import Tensor loss = nn.RMSELoss() input_data = Tensor(np.array([1, 2, 3]), mindspore.float32) target_data = Tensor(np.array([1, 2, 2]), mindspore.float32) output = loss(input_data, target_data) print(output) 0.57735026
MindSpore官方资料 GitHub : https://github.com/mindspore-ai/mindspore Gitee:https : //gitee.com/mindspore/mindspore 官方QQ群 : 871543426