交叉熵
最近在使用lightGBM做二分类的一些工作,用到了交叉熵,发现了使用sklearn当中的库和自己计算的结果并不相同的情况,分析记录如下
交叉熵公式
bce=−1N∑i(yilogpi+(1−yi)log(1−pi))
bce = - \frac{1}{N} \sum_i (y_i log p_i + (1-y_i)log(1-p_i))
bce=−N1i∑(yilogpi+(1−yi)log(1−pi))
- 自定义交叉熵
def logloss_z(trues, preds, sample_weight=1, eps=1e-7):
"""自定义交叉熵"""
preds = np.clip(preds, eps, 1-eps) # 防止log0出现
loss = np.where(trues, -np.log(preds), -np.log(1-preds))
return np.mean(loss * sample_weight)
sklearn.metrics.log_loss
from sklearn.metrics import log_loss
tf.losses.BinaryCrossentropy()
import tensorflow as tf
bce = tf.losses.BinaryCrossentropy()
bce(trues, preds)
交叉熵的一阶,二阶倒数
在用到lightGBM的时候,想自定义交叉熵损失函数,对交叉熵损失函数做一些改动,就需要指明损失函数的一阶二阶导数
一阶导数:
p=sigmoid(x)=11+e−x∂p∂x=p(1−p)
p = sigmoid(x) = \frac{1}{1 + e^{-x}} \\
\frac{\partial{p}}{\partial{x}} = p ( 1 - p )
p=sigmoid(x)=1+e−x1∂x∂p=p(1−p)
grad=∂loss∂x=∂[−ylogp−(1−y)log(1−p)]∂x=∂loss∂p∗∂p∂x=p−y grad= \frac{\partial{loss}}{\partial{x}} = \frac{\partial{[-ylogp - (1-y)log(1-p)}]}{\partial{x}} \\ = \frac{\partial{loss}}{\partial{p}} * \frac{\partial{p}}{\partial{x}} = p - y grad=∂x∂loss=∂x∂[−ylogp−(1−y)log(1−p)]=∂p∂loss∗∂x∂p=p−y
二阶导数:
hess=∂2loss∂x2=p(1−p)
hess = \frac{\partial^2loss}{\partial{x^2}} = p(1-p)
hess=∂x2∂2loss=p(1−p)
FP(假阳性):无病 -> 有病
FN(假阴性):有病 -> 无病,这种情况通常是比较严重的,耽误治疗的时机
−yilogpi-y_ilogp_i−yilogpi:表示所有正样本的预测情况,正->负:FN, 正->正:TP,这一项的值越小说明pip_ipi的值越大,预测的FN越小,所以可以通过增加这一项的权重来减少FN
另外在lightGBM当中使用cross_entropy_lambda计算所得的交叉熵和自定义的交叉熵结果相同
注意
sklearn.metrics.log_loss与 我自定义交叉熵的一点区别
import numpy as np
from sklearn.metrics import log_loss
from scipy.special import softmax, expit
import tensorflow as tf
bce = tf.losses.BinaryCrossentropy()
def logloss_z(trues, preds, sample_weight=1, eps=1e-7):
"""自定义损失函数"""
#preds = np.clip(preds, eps, 1-eps)
loss = np.where(trues, -np.log(preds), -np.log(1-preds))
#return np.mean(loss * sample_weight)
return np.average(loss, weights=sample_weight)
trues = np.array([1, 0])
preds = np.array([0.8, 0.1])
w = np.array([0.1, 0.6])
print(
log_loss(trues, preds, normalize=True,sample_weight=w),
logloss_z(trues, preds, sample_weight=w),
bce(tf.expand_dims(trues, axis=-1), tf.expand_dims(preds, axis=-1), sample_weight=w)
)
- 通过上面的结果可以看到
sklearn.metrics.log_loss使用的是np.average加权平均 tf.bce使用的是np.mean(loss*sample_weight)
参考文章
- 非常不错的一篇树模型自定义损失函数的介绍:https://www.zhangqibot.com/post/ml-custom-loss-lgbm-xgb/
- lightGBM官方教程:https://github.com/microsoft/LightGBM/blob/master/examples/python-guide/advanced_example.py
- sklearn.metrics.log_loss: https://github.com/scikit-learn/scikit-learn/blob/fd237278e/sklearn/metrics/_classification.py#L2118
285



被折叠的 条评论
为什么被折叠?



