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

Keras基于混淆矩阵编写自定义损失函数运行报错求解

问题背景

在Keras中实现二分类任务的自定义损失函数,优化目标为最小化加权错误成本:10 * FalsePositive(假阳性) + 500 * FalseNegative(假阴性),先后两次实现均触发运行报错。

第一版实现(基于sklearn混淆矩阵+pandas)

代码如下:

def custom_loss_func(y_train, y_pred):
    cm=metrics.confusion_matrix(y_train,y_pred)
    cm1 = pd.DataFrame(cm.reshape((1,4)), columns=['TN', 'FP', 'FN', 'TP'])
    cm1 = cm1.fillna(0)
    TC= 10*cm1.FP + 500*cm1.FN
    return float (TC)

# Compiling the ANN
ann.compile(optimizer = 'adam', loss = my_loss_fn, metrics = ['accuracy'])

# Fitting the ANN to the Training set
ann.fit(x_train,y_train,batch_size=32,epochs = 50, class_weight= class_weights)

触发报错:

NotImplementedError: Cannot convert a symbolic tf.Tensor (my_loss_fn/strided_slice:0) to a numpy array. 
This error may indicate that you're trying to pass a Tensor to a NumPy call, which is not supported.

第二版实现(基于TF原生指标)

代码如下:

def my_loss_fn(y_train, y_pred):
    FP = tf.keras.metrics.FalsePositives()
    FP.update_state(y_train, y_pred)
    FP=m.result().numpy()

    FN = tf.keras.metrics.FalseNegatives()
    FN.update_state(y_train, y_pred)
    FN=n.result().numpy()

    # Converted as Keras Tensors
    FP = tf.Variable(m)
    FN = tf.Variable(n)

    loss = 500*FN + 10*FP

    return loss

触发报错:

ValueError(f"No gradients provided for any variable: {variable}. "

 f"Provided `grads_and_vars` is {grads_and_vars}.")
  if vars_with_empty_grads:
 logging.warning(
 ("Gradients do not exist for variables %s when minimizing the loss. "
 "If you're using `model.compile()`, did you forget to provide a `loss`"
 "argument?"),
 ([v.name for v in vars_with_empty_grads]))
错误原因
  • 第一版核心问题:TensorFlow/Keras训练过程中,传入损失函数的y_train和y_pred是动态图模式下的符号张量,不支持直接传入sklearn、pandas等基于numpy实现的非TF原生函数,也不能在图构建阶段将符号张量转为numpy数组,因此触发类型转换错误。
  • 第二版核心问题:虽然调用了TF自带的分类指标接口,但代码中执行.numpy()操作将张量转为普通数值,又新建独立tf.Variable存储结果,完全切断了损失值和模型可训练参数之间的梯度传播链路,反向传播时无法拿到参数对应的梯度,因此触发无梯度报错;同时代码本身存在变量名引用错误(m/n未定义)。
正确实现方法

自定义Keras损失必须全程使用TensorFlow原生可微算子,保证从模型输出到损失值的整个计算路径可导,不能中途插入numpy转换、非TF计算逻辑。
针对加权FP/FN的损失需求,不需要调用混淆矩阵或指标接口,直接基于真实标签和预测概率计算软计数即可(硬阈值转0/1会导致梯度断裂,用概率值计算可保留完整梯度):

import tensorflow as tf

def weighted_cost_loss(y_true, y_pred):
    # 预测概率做数值截断,避免出现log(0)类数值问题,不影响梯度传播
    y_pred = tf.clip_by_value(y_pred, 1e-7, 1 - 1e-7)
    # 假阳性软计数:真实标签为0,预测为正类的概率和
    fp = tf.reduce_sum((1 - y_true) * y_pred)
    # 假阴性软计数:真实标签为1,预测为负类的概率和
    fn = tf.reduce_sum(y_true * (1 - y_pred))
    # 按权重计算总损失
    loss = 10 * fp + 500 * fn
    # 对batch做平均,适配batch训练逻辑,避免损失值随batch大小波动
    return loss / tf.cast(tf.shape(y_true)[0], tf.float32)

# 模型编译,注意:损失已经内置了FN的高权重,不需要额外传入class_weight避免重复加权
ann.compile(optimizer='adam', loss=weighted_cost_loss, metrics=['accuracy', tf.keras.metrics.FalsePositives(), tf.keras.metrics.FalseNegatives()])

# 模型训练
ann.fit(x_train, y_train, batch_size=32, epochs=50, validation_data=(x_val, y_val))

注意:如果模型最后一层没有加sigmoid激活,需要在损失函数内先对logits做sigmoid转换再计算,或者调整计算逻辑适配logits输入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 20:39:20