为何tf.keras的CategoricalCrossentropy接口与手动实现结果存在差异
分类交叉熵手动实现与tf.keras接口结果差异的原因
差异来自tf.keras内置接口的两个默认机制,你手动实现时没有包含这两个处理步骤:
- 数值裁剪(防止数值溢出)
tf.keras.losses.CategoricalCrossentropy 默认有数值稳定优化,会把输入的预测概率裁剪到[1e-7, 1-1e-7]区间(这个阈值由参数epsilon控制,默认值为1e-7),避免计算log(0)出现无穷大的错误。
你第二个测试用例中正类的预测概率是1e-11,远小于1e-7,会被API自动替换为1e-7,计算得-ln(1e-7)≈16.118,和API输出完全一致;而你手动实现没有做裁剪,直接对1e-11取对数得到≈25.328,差异就来源于此。 - 预测值归一化处理
分类交叉熵要求输入的预测值是和为1的合法概率分布,你第一个测试用例的第二个样本预测值[0.5, 0.89, 0.6]的和为1.99,不满足概率分布要求。tf.keras的API会自动对每一行的预测值做归一化,保证每行和为1之后再计算交叉熵,你手动实现没有做这个步骤,直接对原始值计算,自然结果不一致。归一化后计算的平均交叉熵和API输出的0.3239完全匹配。
如果要让手动实现和API结果对齐,可以做两个修改:
- 手动对
y_pred做裁剪:y_pred = np.clip(y_pred, 1e-7, 1-1e-7) - 手动对
y_pred的每一行做归一化:y_pred = y_pred / np.sum(y_pred, axis=1, keepdims=True)
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

