You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Keras自定义损失函数出现NaN及reduction_indices类型错误如何解决

问题原因分析

1 最大值API调用错误

Keras后端的K.max接口作用是对单个张量沿指定维度计算最大值,第二个入参为待降维的轴索引,要求传入int32/int64类型。两次调用均不符合该API的参数要求:

  • 第一次将浮点型阈值作为第二个参数传入,系统误判为轴参数,触发TypeError类型错误
  • 第二次将两个张量放入列表传入K.max,因两个张量形状不匹配无法堆叠计算,触发形状不匹配错误
    要实现两个张量逐元素取最大值的需求,应该使用K.maximum接口,或者直接用更便捷的K.clip接口做范围截断。

2 阈值书写错误

第二次修改代码时使用的阈值是[[00000001]],缺少小数点,实际等价于整数1,完全无法起到避免log输入为0的作用。

3 损失公式错误(核心问题)

当前书写的损失公式不符合二元交叉熵的标准形式:
标准二元交叉熵公式为 -(y_true * log(y_pred) + (1-y_true) * log(1-y_pred)),现有代码中误将乘号写为减号,会导致损失值计算完全偏离预期,甚至出现梯度爆炸,最终输出全为nan。

4 输出层激活缺失(潜在问题)

要计算log(y_pred)和log(1-y_pred),要求y_pred的取值范围必须在(0,1)区间内。如果输出层没有添加sigmoid激活函数,y_pred可以输出任意负数或者大于1的值,直接计算log也会出现nan。

解决方案

步骤1 修正输出层配置

输出维度为1的Dense层必须添加sigmoid激活函数,确保y_pred输出范围在(0,1)之间:

# 输出层示例
output = Dense(1, activation='sigmoid')(x)

步骤2 实现数值稳定的自定义损失

使用K.clip接口截断y_pred的取值范围,同时修正损失公式,完整代码如下:

def loss(self, y_true, y_pred):
    epsilon = 1e-7
    # 截断y_pred避免log输入为0或1
    y_pred_clipped = K.clip(y_pred, epsilon, 1 - epsilon)
    # 正确的二元交叉熵计算
    binary_crossentropy = -(y_true * K.log(y_pred_clipped) + (1 - y_true) * K.log(1 - y_pred_clipped))
    return K.mean(binary_crossentropy, axis=-1)

如果坚持使用逐元素取最大值的方式实现截断,可以替换为如下写法,效果与K.clip一致:

y_pred_clipped = K.maximum(K.minimum(y_pred, 1 - epsilon), epsilon)

内容的提问来源于stack exchange,提问作者mossishahi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 21:36:00