损失函数(loss function)是用来衡量预测值和真实值差距的函数,是模型优化的目标,所以也称之目标函数、优化评分函数。这是机器学习中很重要的性能衡量指标, 评价函数和损失函数相似,只是关注点不同:损失函数用于训练过程,而评价函数用于模型训练完成后(或每一批次训练完成后)的度量,所以这里放到一个篇幅里介绍。 1 损失函数Losses
1.1 keras提供的损失函数
keras提供的损失函数如下,它们有自己适用的应用场景,最常用的是均方误差和交叉熵误差: [tr]编号可用损失函数alias说明[/tr]
1 |
mean_squared_error(y_true, y_pred) |
mse |
MSE 均方误差 |
2 |
mean_absolute_error(y_true, y_pred) |
mae |
MAE 平均绝对值误差 |
3 |
mean_absolute_percentage_error(y_true, y_pred) |
mape |
MAPE 平均绝对百分比误 |
4 |
mean_squared_logarithmic_error(y_true, y_pred) |
msle |
MSLE 对数方差 |
5 |
hinge(y_true, y_pred) |
|
合页 |
6 |
squared_hinge(y_true, y_pred) |
|
平方合页 |
7 |
categorical_hinge(y_true, y_pred) |
|
多类合页 |
8 |
log_cosh(y_true, y_pred) |
logcosh |
双曲余弦对数误差 |
9 |
categorical_crossentropy(y_true, y_pred) |
|
分类交叉熵 |
10 |
sparse_categorical_crossentropy(y_true, y_pred) |
|
稀疏交叉熵 |
11 |
binary_crossentropy(y_true, y_pred) |
bce |
BCE二进制交叉熵 |
12 |
kullback_leibler_divergence(y_true, y_pred) |
kld |
KL散度 |
13 |
poisson(y_true, y_pred) |
|
泊松损失 |
14 |
cosine_proximity(y_true, y_pred) |
|
余弦相似度 |
以下是各个误差函数的详细介绍: 1 mean_squared_error(MSE) mean_squared_error即均方误差,一般用于回归计算,是最常用的损失函数,但在某些情况下,其它损失函数可能更适合。
![]()
losses中的源码为: defmean_squared_error(y_true, y_pred): returnK.mean(K.square(y_pred-y_true), axis=-1)2 mean_absolute_error(MAE) mean_absolute_error即平均绝对误差,一般用于回归计算,与MSE一样都是测量两个向量(预测向量与目标值)之间距离的方法,只不过MSE使用的是平方和的平均值,而MAE使用绝对值的平均值。
![]() 其源码为: defmean_absolute_error(y_true, y_pred): returnK.mean(K.abs(y_pred-y_true), axis=-1)选择MSE还是MAE? MSE是误差的平方和,所以对于异常数据更为敏感。如果异常值表示的反常现象对于业务非常重要,且应当被检测到,那么我们就应当使用MSE。另一方面,如果我们认为异常值仅表示损坏数据而已,那么我们应当选择MAE作为损失函数。 3 mean_absolute_percentage_error (MAPE) 平均绝对值百分比误差,它是一种相对度量,以百分比为单位而不是变量的单位,一般用于回归计算,一般用于各种时间序列模型的预测,如销量预测等。
![]()
其源码为: defmean_absolute_percentage_error(y_true, y_pred): diff = K.abs((y_true-y_pred)/K.clip(K.abs(y_true), K.epsilon(), np.inf)) return100.*K.mean(diff, axis=-1)4 mean_squared_logarithmic_error(MSLE) 对数方差,适用于目标具有指数增长趋势,例如:人口数量,跨年度商品的平均销售额等。
![]()
其源码为: defmean_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.) returnK.mean(K.square(first_log-second_log), axis=-1) 5 hinge (Hinge) 合页,通常用于“maximum-margin”二分类任务中,如SVM支持向量机
![]()
其源码为: defhinge(y_true, y_pred): returnK.mean(K.maximum(1.-y_true*y_pred,0.), axis=-1) 6 squared_hinge (SH) 平方合页,与hinge类似,最大值时加上平方值,与常规hinge合页损失相比,平方合页损失函数对离群值惩罚更严厉,一般多用于二分类计算。
![]()
其源码为: defsquared_hinge(y_true, y_pred): returnK.mean(K.square(K.maximum(1.-y_true*y_pred,0.)), axis=-1) 7 categorical_hinge 多类合页,更多用于多分类形式。 其源码为: defcategorical_crossentropy(y_true, y_pred): '''Expects a binary class matrix instead of a vector of scalar classes. ''' returnK.categorical_crossentropy(y_pred, y_true)8 logcosh 双曲余弦对数误差函数,它比MSE损失更平滑。对于较小的 x , logcosh近似等于 (x ** 2) / 2 。对于大的 x,近似于 abs(x) - log2 。这表示 'logcosh' 与均方误差算法大致相同,但是不会受到偶发性错误预测的强烈影响。
![]()
其源码为:
deflogcosh(true, pred): loss = np.log(np.cosh(pred-true))returnnp.sum(loss) 9 categorical_crossentropy(CCE) 分类交叉熵,主要用于分类算法,当使用categorical_crossentropy损失函数时,目标值格式应该为one-hot编码格式。可以使用keras的to_categorical(int_labels, num_classes=None)将整数目标值转为one-hot编码
![]()
其源码为: defcategorical_crossentropy(y_true, y_pred): '''Expects a binary class matrix instead of a vector of scalar classes. ''' returnK.categorical_crossentropy(y_pred, y_true)10 sparse_categorical_crossentropy(SCCE) 稀疏交叉熵,与CCE分类交叉熵相类似,主要用于分类算法,只是目标格式输出值略有不同,CCE以one-hot编码输出,而SCEE直接转化为索引值进行输出。 其源码为: defsparse_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. ''' returnK.sparse_categorical_crossentropy(y_pred, y_true)11 binary_crossentropy(BCE) 二进制交叉熵,更适用于二分类,对于二分类问题,BCE的运行效率会更高,注意:如果使用BCE作为损失函数,则节点介于[0, 1]之间,意味着在最终输出需要使用sigmoid激活函数。
![]()
其源码为: defbinary_crossentropy(y_true, y_pred): returnK.mean(K.binary_crossentropy(y_pred, y_true), axis=-1)12 kullback_leibler_divergence KL散度,用于分类计算,通过衡量预测值概率分布到真值概率分布的相似度差异,在运动捕捉里面可以衡量未添加标签的运动与已添加标签的运动,进而进行运动的分类。
![]()
其源码为: defkullback_leibler_divergence(y_true, y_pred): y_true = K.clip(y_true, K.epsilon(),1) y_pred = K.clip(y_pred, K.epsilon(),1) returnK.sum(y_true*K.log(y_true/y_pred), axis=-1) 13 poisson 泊松损失函数,用于回归算法,一般用于计算事件发生的概率。
![]()
其源码为: defpoisson(y_true, y_pred): returnK.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,而与预测值和目标值之间的接近程度无关。
![]()
其源码为: defcosine_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提供的损失函数基本够用,某些特殊情况,我们可以自己定义损失函数。 defmy_loss(y_true,y_pred): returnK.mean((y_pred-y_true),axis =-1)
model.compile(loss=my_loss, optimizer='SGD', metrics=['accuracy'])注意:keras 损失函数以(y_true, y_pred)作为入参。 1.3 keras损失函数的使用
fromkerasimportlosses
# 写法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: importtensorflowastf importtensorflow.kerasaskeras importnumpyasnp
print(keras.__version__)
(x_train, y_train), (x_valid, y_valid) = keras.datasets.mnist.load_data() assertx_train.shape == (60000,28,28) assertx_valid.shape == (10000,28,28) asserty_train.shape == (60000,) asserty_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编码,代码如下: importtensorflowastf importtensorflow.kerasaskeras importnumpyasnp
print(keras.__version__)
(x_train, y_train), (x_valid, y_valid) = keras.datasets.mnist.load_data() assertx_train.shape == (60000,28,28) assertx_valid.shape == (10000,28,28) asserty_train.shape == (60000,) asserty_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个评价函数。 [tr]编号可用的评价函数alias说明[/tr]
1 |
accuracy(y_true, y_pred) |
acc |
对比结果 |
2 |
binary_accuracy(y_true, y_pred, threshold=0.5) |
|
可用于二元分类的评价(大于threshold设为1,否则设为0) |
3 |
categorical_accuracy(y_true, y_pred) |
|
可用于多元分类one-hot标签的评价(one-hot标签) |
|
sparse_categorical_accuracy(y_true, y_pred) |
|
可用于多元分类的评价(非one-hot标签) |
5 |
top_k_categorical_accuracy(y_true, y_pred, k=5) |
|
可用于前k项分类的评价,前k值中存在目标类别即认为预测准确(one-hot标签) |
6 |
sparse_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的末尾。
|