TensorFlow训练的二元交叉熵损失为何与sklearn计算结果不一致
TensorFlow二元交叉熵与scikit-learn log_loss数值差异原因说明
二者底层的二元交叉熵数学计算逻辑没有本质差异,你观察到的数值差基本都是使用场景、参数配置的差异导致的,常见原因如下:
- 损失计算的数据集状态差异
TensorFlow训练时输出的epoch损失,默认是该轮训练过程中每一批次损失的滑动平均值,计算时包含了本轮所有训练样本的前向传播损失,且训练过程中模型权重是动态更新的:第一个批次计算损失用的是本轮初始权重,最后一个批次用的是本轮更新后的最终权重。而你调用sklearn的log_loss计算时,用的是本轮训练完成后的最终固定权重预测的所有样本结果,计算的是静态权重下的全局损失,天然会比滑动平均的训练损失更低。 - 正则项包含逻辑差异
如果你在TensorFlow模型中添加了L1、L2正则化,或者使用了Dropout等仅训练时生效的层,TensorFlow输出的损失是原始预测损失+正则项损失的总和,而sklearn的log_loss只计算预测值和标签的交叉熵,不会包含任何正则项损失,这也会导致TF输出的损失更高。 - 默认参数配置差异
TensorFlow的BinaryCrossentropy默认参数和sklearn的log_loss默认参数存在两处关键差异:- TF的损失默认对batch内样本取平均,sklearn默认也是取平均,但如果你的TF损失设置了
reduction=SUM之类的参数,数值会直接差出样本量级 - TF的
BinaryCrossentropy默认开启from_logits=False,要求输入是经过sigmoid后的概率值,如果你实际输出的是未经过sigmoid的logits,TF会自动做数值稳定的sigmoid+交叉熵计算,而sklearn的log_loss默认要求输入是概率值,如果传入logits会直接计算出错误的低损失 - 二者的数值裁剪阈值不同:TF默认会把预测概率裁剪到
[epsilon, 1-epsilon]避免log(0)的问题,sklearn的默认裁剪阈值和TF的默认epsilon(通常为1e-7)存在差异,也会带来微小的数值偏差。
- TF的损失默认对batch内样本取平均,sklearn默认也是取平均,但如果你的TF损失设置了
验证方法:拿固定的一批训练样本,用训练完成后的静态模型预测得到概率值,分别传给没有加任何正则项的TF
BinaryCrossentropy接口和sklearn的log_loss接口,对齐参数后二者的计算结果会几乎完全一致。
内容的提问来源于stack exchange,提问作者Jeremy
相关产品推荐
相关产品推荐

