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

Keras/TensorFlow自定义损失函数拟合x1+x2²结果异常如何排查

自定义损失拟合f(x1,x2)=x1+x2²结果异常修复

你的代码有3个核心问题,直接导致训练结果偏离预期:

  • 输出层激活函数错误:最后一层Dense用了tanh激活,该激活的输出值域严格限制在(-1, 1)区间,且在值域两端梯度趋近于0,不仅无法输出超出区间的结果,还会大幅降低训练收敛效率。回归任务的输出层默认使用线性激活即可,不要额外加激活函数。
  • 损失函数传参逻辑错误:你在模型编译阶段就把整个数据集的X1、X2固定传入了损失闭包,训练时框架会按batch抽取样本、默认打乱数据顺序,损失计算时用到的X1/X2和当前batch的预测值y_pred完全不匹配,算出来的损失没有任何参考意义。
  • 无意义的伪标签设计:你额外构造全零列当y_true完全是多余操作,既可以直接把x1+x2²的计算结果作为真实标签传入(和普通监督回归任务完全一致),也可以通过模型内部绑定损失的方式实现无监督训练,不需要凑数传参。

最简修复方案(推荐)

不需要写复杂的自定义损失闭包,直接计算目标值作为标签,用内置MSE损失即可,MSE的计算逻辑和你预期的[(X1+X2²)-y_pred]^2完全一致:

import keras
import numpy as np
import pandas as pd

df = pd.read_csv('inputs.csv')
# 取输入特征
X = df[['X1', 'X2']].astype(np.float32)
# 直接计算目标值作为标签,不需要构造全零列
y = (df['X1'] + df['X2'] ** 2).astype(np.float32)

model = keras.models.Sequential()
model.add(keras.layers.Dense(20, activation='tanh', input_shape=(2,)))
model.add(keras.layers.Dense(20, activation='tanh'))
# 最后一层移除tanh激活,使用默认线性激活
model.add(keras.layers.Dense(1))

model.compile(optimizer='adam', loss='mse')
# 训练时指定batch_size,避免样本错位
model.fit(X, y, epochs=400, batch_size=32)

test_data = np.array([0.5, 0.6])
print(model.predict(test_data.reshape(1, 2), batch_size=1))

运行后对测试样本[0.5, 0.6]的预测值会非常接近预期值0.86。


纯无监督写法(不提前计算标签)

如果坚持要完全走无监督逻辑、不提前生成标签,需要通过模型绑定损失的方式,保证损失计算时拿到的是当前batch的输入数据,而不是固定的全局数据集切片:

import keras
import numpy as np
import pandas as pd
import tensorflow as tf

df = pd.read_csv('inputs.csv')
X = df[['X1', 'X2']].astype(np.float32)
# 伪标签,损失计算中不会用到
dummy_y = np.zeros((len(X), 1), dtype=np.float32)

# 用函数式API构建模型,方便获取输入张量
inputs = keras.Input(shape=(2,))
x = keras.layers.Dense(20, activation='tanh')(inputs)
x = keras.layers.Dense(20, activation='tanh')(x)
outputs = keras.layers.Dense(1)(x)
model = keras.Model(inputs=inputs, outputs=outputs)

# 从当前batch的输入中取x1、x2计算目标值,不会出现样本错位
def unsup_loss(y_true, y_pred):
    x1 = tf.expand_dims(inputs[:, 0], axis=-1)
    x2 = tf.expand_dims(inputs[:, 1], axis=-1)
    target = x1 + tf.square(x2)
    return tf.reduce_mean(tf.square(target - y_pred))

model.compile(optimizer='adam', loss=unsup_loss)
model.fit(X, dummy_y, epochs=400, batch_size=32)

注意:做回归任务时,输出层不要随意添加有值域限制的激活函数(如tanh、sigmoid),除非你已经把目标值归一化到了对应激活的值域范围内,否则模型永远无法拟合出正确结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:03:28