RISC-V MCU中文社区

Keras入门第3讲keras常用的损失函数Losses与评价函数Metrics

发表于 2023-06-06 16:50:16
0
7560
1

损失函数(loss function)是用来衡量预测值和真实值差距的函数,是模型优化的目标,所以也称之目标函数、优化评分函数。这是机器学习中很重要的性能衡量指标, 评价函数和损失函数相似,只是关注点不同:损失函数用于训练过程,而评价函数用于模型训练完成后(或每一批次训练完成后)的度量,所以这里放到一个篇幅里介绍。

1 损失函数Losses

1.1 keras提供的损失函数

keras提供的损失函数如下,它们有自己适用的应用场景,最常用的是均方误差和交叉熵误差:

编号可用损失函数alias说明
1mean_squared_error(y_true, y_pred)mseMSE 均方误差
2mean_absolute_error(y_true, y_pred)maeMAE 平均绝对值误差
3mean_absolute_percentage_error(y_true, y_pred)mapeMAPE 平均绝对百分比误
4mean_squared_logarithmic_error(y_true, y_pred)msleMSLE 对数方差
5hinge(y_true, y_pred)合页
6squared_hinge(y_true, y_pred)平方合页
7categorical_hinge(y_true, y_pred)多类合页
8log_cosh(y_true, y_pred)logcosh双曲余弦对数误差
9categorical_crossentropy(y_true, y_pred)分类交叉熵
10sparse_categorical_crossentropy(y_true, y_pred)稀疏交叉熵
11binary_crossentropy(y_true, y_pred)bceBCE二进制交叉熵
12kullback_leibler_divergence(y_true, y_pred)kldKL散度
13poisson(y_true, y_pred)泊松损失
14cosine_proximity(y_true, y_pred)余弦相似度

以下是各个误差函数的详细介绍:

1 mean_squared_error(MSE)

mean_squared_error即均方误差,一般用于回归计算,是最常用的损失函数,但在某些情况下,其它损失函数可能更适合。


losses中的源码为:

def mean_squared_error(y_true, y_pred):
   return K.mean(K.square(y_pred - y_true), axis=-1)

2 mean_absolute_error(MAE)

mean_absolute_error即平均绝对误差,一般用于回归计算,与MSE一样都是测量两个向量(预测向量与目标值)之间距离的方法,只不过MSE使用的是平方和的平均值,而MAE使用绝对值的平均值。

其源码为:

def mean_absolute_error(y_true, y_pred):
return K.mean(K.abs(y_pred - y_true), axis=-1)

选择MSE还是MAE?

MSE是误差的平方和,所以对于异常数据更为敏感。如果异常值表示的反常现象对于业务非常重要,且应当被检测到,那么我们就应当使用MSE。另一方面,如果我们认为异常值仅表示损坏数据而已,那么我们应当选择MAE作为损失函数。

3 mean_absolute_percentage_error (MAPE)

平均绝对值百分比误差,它是一种相对度量,以百分比为单位而不是变量的单位,一般用于回归计算,一般用于各种时间序列模型的预测,如销量预测等。


其源码为:

def mean_absolute_percentage_error(y_true, y_pred):
   diff = K.abs((y_true - y_pred) / K.clip(K.abs(y_true), K.epsilon(), np.inf))
   return 100. * K.mean(diff, axis=-1)

4 mean_squared_logarithmic_error(MSLE)

对数方差,适用于目标具有指数增长趋势,例如:人口数量,跨年度商品的平均销售额等。


其源码为:

def mean_squared_logarithmic_error(y_true, y_pred):
   first_log = K.log(K.clip(y_pred, K.epsilon(), np.inf) + 1.)
   second_log = K.log(K.clip(y_true, K.epsilon(), np.inf) + 1.)
   return K.mean(K.square(first_log - second_log), axis=-1)

5 hinge (Hinge)

合页,通常用于“maximum-margin”二分类任务中,如SVM支持向量机


其源码为:

def hinge(y_true, y_pred):
   return K.mean(K.maximum(1. - y_true * y_pred, 0.), axis=-1)

6 squared_hinge (SH)

平方合页,与hinge类似,最大值时加上平方值,与常规hinge合页损失相比,平方合页损失函数对离群值惩罚更严厉,一般多用于二分类计算。


其源码为:

def squared_hinge(y_true, y_pred):
   return K.mean(K.square(K.maximum(1. - y_true * y_pred, 0.)), axis=-1)

7 categorical_hinge

多类合页,更多用于多分类形式。

其源码为:

def categorical_crossentropy(y_true, y_pred):
   '''Expects a binary class matrix instead of a vector of scalar classes.
  '''
   return K.categorical_crossentropy(y_pred, y_true)

8 logcosh

双曲余弦对数误差函数,它比MSE损失更平滑。对于较小的 x , logcosh近似等于 (x ** 2) / 2 。对于大的 x,近似于 abs(x) - log2 。这表示 'logcosh' 与均方误差算法大致相同,但是不会受到偶发性错误预测的强烈影响。


其源码为:

def logcosh(true, pred):
   loss = np.log(np.cosh(pred - true))return np.sum(loss)

9 categorical_crossentropy(CCE)

分类交叉熵,主要用于分类算法,当使用categorical_crossentropy损失函数时,目标值格式应该为one-hot编码格式。可以使用keras的to_categorical(int_labels, num_classes=None)将整数目标值转为one-hot编码


其源码为:

def categorical_crossentropy(y_true, y_pred):
   '''Expects a binary class matrix instead of a vector of scalar classes.
  '''
   return K.categorical_crossentropy(y_pred, y_true)

10 sparse_categorical_crossentropy(SCCE)

稀疏交叉熵,与CCE分类交叉熵相类似,主要用于分类算法,只是目标格式输出值略有不同,CCE以one-hot编码输出,而SCEE直接转化为索引值进行输出。

其源码为:

def sparse_categorical_crossentropy(y_true, y_pred):
   '''expects an array of integer classes.
  Note: labels shape must have the same number of dimensions as output shape.
  If you get a shape error, add a length-1 dimension to labels.
  '''
   return K.sparse_categorical_crossentropy(y_pred, y_true)

11 binary_crossentropy(BCE)

二进制交叉熵,更适用于二分类,对于二分类问题,BCE的运行效率会更高,注意:如果使用BCE作为损失函数,则节点介于[0, 1]之间,意味着在最终输出需要使用sigmoid激活函数。


其源码为:

def binary_crossentropy(y_true, y_pred):
   return K.mean(K.binary_crossentropy(y_pred, y_true), axis=-1)

12 kullback_leibler_divergence

KL散度,用于分类计算,通过衡量预测值概率分布到真值概率分布的相似度差异,在运动捕捉里面可以衡量未添加标签的运动与已添加标签的运动,进而进行运动的分类。


其源码为:

def kullback_leibler_divergence(y_true, y_pred):
   y_true = K.clip(y_true, K.epsilon(), 1)
   y_pred = K.clip(y_pred, K.epsilon(), 1)
   return K.sum(y_true * K.log(y_true / y_pred), axis=-1)

13 poisson

泊松损失函数,用于回归算法,一般用于计算事件发生的概率。


其源码为:

def poisson(y_true, y_pred):
   return K.mean(y_pred - y_true * K.log(y_pred + K.epsilon()), axis=-1)

14 cosine_proximity

余弦相似度,预测值与真实标签的余弦距离平均值的相反数,它是一个介于-1和1之间的数字。当它是负数时在-1和0之间,0表示正交,越接近-1 表示相似性越大,值越接近1表示不同性越大,这使得它在设置中可用作损失函数。如果' y_true '或' y_pred '是一个零向量,余弦无论预测的接近程度如何,则相似度都为 0,而与预测值和目标值之间的接近程度无关。


其源码为:

def cosine_proximity(y_true, y_pred):
   y_true = K.l2_normalize(y_true, axis=-1)
   y_pred = K.l2_normalize(y_pred, axis=-1)
   return -K.mean(y_true * y_pred, axis=-1)

1.2 自定义损失函数

一般情况下,并不需要我们自定义损失函数,keras提供的损失函数基本够用,某些特殊情况,我们可以自己定义损失函数。

def my_loss(y_true,y_pred):
   return K.mean((y_pred - y_true),axis = -1)

model.compile(loss=my_loss, optimizer='SGD', metrics=['accuracy'])

注意:keras 损失函数以(y_true, y_pred)作为入参。

1.3 keras损失函数的使用

from keras import losses

# 写法1:
model.compile(loss='mean_squared_error', optimizer='sgd')

# 写法2:
model.compile(loss=losses.mean_squared_error, optimizer='sgd')

# 写法3:如果有别名,也可以使用别名
model.compile(loss='mse', optimizer='sgd')

1.4 loss函数一般的使用经验

  • 回归问题使用mean_squared_error(均方误差)

  • 二分类问题使用 binary_crossentropy

  • 多分类问题使用 categorical_crossentropy (最后一层使用softmax激活函数),非one-hot编码使用 sparse_categorical_crossentropy

下面比较一下categorical_crossentropy(分类交叉熵)与 sparse_categorical_crossentropy(稀疏交叉熵)

使用sparse_categorical_crossentropy:

import tensorflow as tf
import tensorflow.keras as keras
import numpy as np

print(keras.__version__)

(x_train, y_train), (x_valid, y_valid) = keras.datasets.mnist.load_data()
assert x_train.shape == (60000, 28, 28)
assert x_valid.shape == (10000, 28, 28)
assert y_train.shape == (60000,)
assert y_valid.shape == (10000,)
print("y_valid type is %s" % (y_valid.shape))
# step1: use sequential
model = keras.models.Sequential()

# step2: add layer
model.add(keras.layers.Flatten(input_shape=(x_train.shape[1], x_train.shape[2])))
model.add(keras.layers.Dense(units=784, activation="relu", input_dim=784))
model.add(keras.layers.Dense(units=10, activation="softmax"))

# step3: compile model
model.compile(optimizer="Adam", loss='sparse_categorical_crossentropy', metrics=['accuracy'])

print("model:")
model.summary()

# step4: train
model.fit(x_train, y_train, batch_size=64, epochs=5)

# step5: evaluate model
model.evaluate(x_valid, y_valid)

# save model
#model.save('keras_mnist.h5')

img = x_valid[0]
img = np.reshape(img, (-1, 28, 28))
output = model.predict(img)
print("output type is %s" % (type(output)))
print(output)
predict_num = np.argmax(output, axis = 1) # 需要使用np.argmax找到最大值
print("predict num is %d" % predict_num)

使用categorical_crossentropy:

将上述代码的loss直接换为categorical_crossentropy,运行时会报错

ValueError: Shapes (None, 1) and (None, 10) are incompatible

需要将label转换为one-hot编码,代码如下:

import tensorflow as tf
import tensorflow.keras as keras
import numpy as np

print(keras.__version__)

(x_train, y_train), (x_valid, y_valid) = keras.datasets.mnist.load_data()
assert x_train.shape == (60000, 28, 28)
assert x_valid.shape == (10000, 28, 28)
assert y_train.shape == (60000,)
assert y_valid.shape == (10000,)

y_train_cate = keras.utils.to_categorical(y_train, 10)    # 将y_train转为one-hot编码
y_valid_cate = keras.utils.to_categorical(y_valid, 10)    # 将y_valid转为one-hot编码
print("y_valid shape is %d" % (y_valid.shape))
# step1: use sequential
model = keras.models.Sequential()

# step2: add layer
model.add(keras.layers.Flatten(input_shape=(x_train.shape[1], x_train.shape[2])))
model.add(keras.layers.Dense(units=784, activation="relu", input_dim=784))
model.add(keras.layers.Dense(units=10, activation="softmax"))

# step3: compile model
model.compile(optimizer="Adam", loss='categorical_crossentropy', metrics=['accuracy'])  # loss使用categorical_crossentropy

print("model:")
model.summary()

# step4: train
model.fit(x_train, y_train_cate, batch_size=64, epochs=5)

# step5: evaluate model
model.evaluate(x_valid, y_valid_cate)                                                   # 评估时使用categorical_crossentropy

# save model
#model.save('keras_mnist.h5')

img = x_valid[0]
img = np.reshape(img, (-1, 28, 28))
output = model.predict(img)
print(output.shape)
print(output)
predict_num = np.argmax(output, axis = 1)
print("predict num is %d" % predict_num)

目前只是比较了使用方法的不同,后续有时间分析一下不同loss函数的内在差异。

2 评价函数Metrics

评价函数和损失函数相似,不同的是损失函数用于训练过程(参与反向传播),而评价函数仅用于模型的度量,记录在每个epoch的末尾。

2.1 keras中新增的6个评价函数

在应用方面,keras.losses中定义的所有函数均可作为评价函数使用,此外,keras.metrics额外定义了6个评价函数。

编号可用的评价函数alias说明
1accuracy(y_true, y_pred)acc对比结果
2binary_accuracy(y_true, y_pred, threshold=0.5)可用于二元分类的评价(大于threshold设为1,否则设为0)
3categorical_accuracy(y_true, y_pred)可用于多元分类one-hot标签的评价(one-hot标签)
sparse_categorical_accuracy(y_true, y_pred)可用于多元分类的评价(非one-hot标签)
5top_k_categorical_accuracy(y_true, y_pred, k=5)可用于前k项分类的评价,前k值中存在目标类别即认为预测准确(one-hot标签)
6sparse_top_k_categorical_accuracy(y_true, y_pred, k=5)可用于前k项分类的评价(非one-hot标签)

2.2 keras中Metrics的使用

# 可以测量多个指标 metrics 入参为列表
model.compile(loss='mse', optimizer='SGD', metrics=['accuracy', 'mse'])

这样就可以同时评估accuracy以及mse了, 记录在每个epoch的末尾。

参考:

  1. Keras教学

  2. 深度学习 - 16.TF x Keras Losses 常见损失函数

  3. Tensorflow 2.0 深度学习实战 —— 详细介绍损失函数、优化器、激活函数、多层感知机的实现原理Python 机器学习实战 —— 监督学习(上)

  4. 机器学习从业者必知的5种回归损失函数

  5. Keras.metrics中的accuracy总结

  6. categorical_crossentropy与sparse_categorical_crossentropy有什么区别?

  7. Keras中的多分类损失函数用法categorical_crossentropy

  8. 解析损失函数之categorical_crossentropy loss与 Hinge loss - 简书 (jianshu.com)

喜欢1
用户评论
sureZ-ok

sureZ-ok 实名认证

懒的都不写签名

积分
问答
粉丝
关注
专栏作者
  • RV-STAR 开发板
  • RISC-V处理器设计系列课程
  • 培养RISC-V大学土壤 共建RISC-V教育生态
RV-STAR 开发板