交叉熵相关知识

交叉熵

最近在使用lightGBM做二分类的一些工作,用到了交叉熵,发现了使用sklearn当中的库和自己计算的结果并不相同的情况,分析记录如下

交叉熵公式
b c e = − 1 N ∑ i ( y i l o g p i + ( 1 − y i ) l o g ( 1 − p i ) ) bce = - \frac{1}{N} \sum_i (y_i log p_i + (1-y_i)log(1-p_i)) bce=N1i(yilogpi+(1yi)log(1pi))

  1. 自定义交叉熵
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)

  1. sklearn.metrics.log_loss
from sklearn.metrics import log_loss
  1. tf.losses.BinaryCrossentropy()
import tensorflow as tf
bce = tf.losses.BinaryCrossentropy()
bce(trues, preds)

交叉熵的一阶,二阶倒数

在用到lightGBM的时候,想自定义交叉熵损失函数,对交叉熵损失函数做一些改动,就需要指明损失函数的一阶二阶导数

一阶导数:
p = s i g m o i d ( x ) = 1 1 + 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+ex1xp=p(1p)

g r a d = ∂ l o s s ∂ x = ∂ [ − y l o g p − ( 1 − y ) l o g ( 1 − p ) ] ∂ x = ∂ l o s s ∂ 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=xloss=x[ylogp(1y)log(1p)]=plossxp=py

二阶导数:
h e s s = ∂ 2 l o s s ∂ x 2 = p ( 1 − p ) hess = \frac{\partial^2loss}{\partial{x^2}} = p(1-p) hess=x22loss=p(1p)

FP(假阳性):无病 -> 有病
FN(假阴性):有病 -> 无病,这种情况通常是比较严重的,耽误治疗的时机

− y i l o g p i -y_ilogp_i yilogpi:表示所有正样本的预测情况,正->负:FN, 正->正:TP,这一项的值越小说明 p i p_i pi的值越大,预测的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

你可能感兴趣的:(学习笔记,机器学习)