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

如何为多输出Keras模型编写接收所有输出的自定义损失函数?

解决多输出Keras模型自定义损失函数的OperatorNotAllowedInGraphError错误

错误根源

在TensorFlow 2.8.4的多输出Keras模型中,当使用继承自tf.keras.losses.Loss的自定义损失类时,Keras会将多个输出对应的真实值(y_true)和预测值(y_pred)堆叠成单个张量传入call方法,而非你假设的张量列表。此时尝试解包张量(y_true1, y_true2 = y_true)会触发迭代张量的操作,这在TensorFlow计算图模式下是被禁止的,从而抛出OperatorNotAllowedInGraphError。


解决方案

方案1:改用函数式自定义损失(推荐)

函数式损失会直接接收对应多个输出的y_true和y_pred列表,完全匹配你最初的代码逻辑:

import numpy as np
from tensorflow.keras import Model, Input
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import Adam
import tensorflow as tf

n_samples = 1000
n_features = 10
X = np.random.random((n_samples, n_features))
Y = [np.random.random((n_samples, 1)),
     np.random.random((n_samples, 1))]

# 定义函数式自定义损失
def custom_loss(y_true, y_pred):
    y_true1, y_true2 = y_true
    y_pred1, y_pred2 = y_pred

    mse1 = tf.reduce_mean(tf.square(y_true1 - y_pred1))
    mse2 = tf.reduce_mean(tf.square(y_true2 - y_pred2))

    return mse1 + mse2

# 构建多输出模型
input_layer = Input(shape=(n_features,))
x = Dense(32, activation='relu')(input_layer)
outputs = [Dense(1)(x), Dense(1)(x)]

model = Model(inputs=input_layer, outputs=outputs)
model.compile(optimizer=Adam(), loss=custom_loss)

model.fit(X, Y, epochs=2, batch_size=32)

方案2:修改Loss类处理堆叠后的张量

如果坚持使用Loss子类,可通过张量切片分离出两个输出对应的真实值和预测值:

import numpy as np
from tensorflow.keras import Model, Input
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import Adam
import tensorflow as tf

n_samples = 1000
n_features = 10
X = np.random.random((n_samples, n_features))
Y = [np.random.random((n_samples, 1)),
     np.random.random((n_samples, 1))]

class CustomLoss(tf.keras.losses.Loss):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def call(self, y_true, y_pred):
        # 从堆叠张量中切片获取两个输出的对应值
        y_true1 = y_true[:, 0:1]
        y_true2 = y_true[:, 1:2]
        y_pred1 = y_pred[:, 0:1]
        y_pred2 = y_pred[:, 1:2]

        mse1 = tf.reduce_mean(tf.square(y_true1 - y_pred1))
        mse2 = tf.reduce_mean(tf.square(y_true2 - y_pred2))

        return mse1 + mse2

# 构建多输出模型
input_layer = Input(shape=(n_features,))
x = Dense(32, activation='relu')(input_layer)
outputs = [Dense(1)(x), Dense(1)(x)]

model = Model(inputs=input_layer, outputs=outputs)
model.compile(optimizer=Adam(), loss=CustomLoss())

model.fit(X, Y, epochs=2, batch_size=32)

方案3:为每个输出指定单独的损失函数

若两个输出的损失逻辑独立,可直接为每个输出分配单独的MSE损失,Keras会自动将总损失求和:

import numpy as np
from tensorflow.keras import Model, Input
from tensorflow.keras.layers import Dense
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.losses import MeanSquaredError

n_samples = 1000
n_features = 10
X = np.random.random((n_samples, n_features))
Y = [np.random.random((n_samples, 1)),
     np.random.random((n_samples, 1))]

# 构建多输出模型
input_layer = Input(shape=(n_features,))
x = Dense(32, activation='relu')(input_layer)
outputs = [Dense(1)(x), Dense(1)(x)]

model = Model(inputs=input_layer, outputs=outputs)
# 为每个输出指定MSE损失,总损失为两者之和
model.compile(optimizer=Adam(), loss=[MeanSquaredError(), MeanSquaredError()])

model.fit(X, Y, epochs=2, batch_size=32)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:54:58