在keras中构建多输出模型时出错

error in constructing multioutput model in keras

我正在尝试在 Keras 中创建多输出模型。该模型以卷积开始,旨在堆叠两个独立的密集层的结果。我为回归任务创建了一些随机数据,其中 x1 是输入,df 是标签。 df 包含三列。在定义训练和测试拆分并形成模型后,我在拟合模型时收到错误消息。谁能帮我更正我的代码?

x1 = np.random.rand(500, 244, 244, 20) 
df = pd.DataFrame(np.random.uniform(0,1,size=(500, 3)), columns=list('XYZ'))     
x_train, x_test, y_train, y_test = train_test_split(x1,df ,test_size=0.2)

n1_y_train=y_train['X'].values
n1_y_test=y_test['X'].values

n2_y_train=y_train['Y'].values
n2_y_test=y_test['Y'].values

n3_y_train=y_train['Z'].values
n3_y_test=y_test['Z'].values

train_shape = x_train.shape

inputs = layers.Input(shape = train_shape[1:])

x = layers.Conv2D(16, (3,3), activation='relu', padding="same")(inputs)
x = layers.Flatten()(x)

# ‌section1:
l1 = layers.Dense(16, activation='relu')(x)
l1 = layers.Dense(1)(l1)

# ‌section2:
l2 = layers.Dense(32, activation='relu')(x)
l2 = layers.Dense(1)(l2)

output1 = tf.reduce_mean(tf.stack([l1, l2], axis=0), axis=0, name = "output1")
output2 = tf.reduce_mean(tf.stack([l1, l2], axis=0), axis=0, name = "output2")
output3 = tf.reduce_mean(tf.stack([l1, l2], axis=0), axis=0, name = "output3")

model = tf.keras.models.Model(inputs, [output1,output2,output3])


model.compile(
        optimizer=tf.keras.optimizers.Adam(),
        loss= tf.keras.losses.mse,
        metrics=tf.keras.metrics.RootMeanSquaredError(name="rmse"))

history = model.fit(x_train,{"output1": n1_y_train, "output2": n2_y_train, "output3": n3_y_train},
validation_data = (x_test,{"output1": n1_y_test, "output2": n2_y_test, "output3": n3_y_test}),
verbose=2,
epochs=100,
batch_size=32)

错误:

ValueError: Found unexpected losses or metrics that do not correspond to any Model output: dict_keys(['output1', 'output2', 'output3']). Valid mode output names: ['tf.math.reduce_mean', 'tf.math.reduce_mean_1', 'tf.math.reduce_mean_2']. Received struct is: {'output1': <tf.Tensor 'IteratorGetNext:1' shape=(None,) dtype=float32>, 'output2': <tf.Tensor 'IteratorGetNext:2' shape=(None,) dtype=float32>, 'output3': <tf.Tensor 'IteratorGetNext:3' shape=(None,) dtype=float32>}.

您应该用 Lambda 层包裹输出层并使用 tf.concat 而不是 tf.stack。通过使用 Lambda 层,您可以明确设置输出的名称,这些名称将由您的模型捕获。这是一个工作示例:

import pandas as pd
import numpy as np
import tensorflow as tf
from sklearn.model_selection import train_test_split

x1 = np.random.rand(10, 244, 244, 20) 
df = pd.DataFrame(np.random.uniform(0,1,size=(10, 3)), columns=list('XYZ'))     
x_train, x_test, y_train, y_test = train_test_split(x1,df ,test_size=0.2)

n1_y_train=y_train['X'].values
n1_y_test=y_test['X'].values

n2_y_train=y_train['Y'].values
n2_y_test=y_test['Y'].values

n3_y_train=y_train['Z'].values
n3_y_test=y_test['Z'].values

train_shape = x_train.shape
inputs = tf.keras.layers.Input(shape = train_shape[1:])

x = tf.keras.layers.Conv2D(16, (3,3), activation='relu', padding="same")(inputs)
x = tf.keras.layers.Flatten()(x)
l1 = tf.keras.layers.Dense(16, activation='relu')(x)
l1 = tf.keras.layers.Dense(1)(l1)
l2 = tf.keras.layers.Dense(32, activation='relu')(x)
l2 = tf.keras.layers.Dense(1)(l2)

output1 = tf.keras.layers.Lambda(lambda x: tf.reduce_mean(x, axis=1, keepdims=True), name='output1')(tf.concat([l1, l2], axis=1))
output2 = tf.keras.layers.Lambda(lambda x: tf.reduce_mean(x, axis=1, keepdims=True), name='output2')(tf.concat([l1, l2], axis=1))
output3 = tf.keras.layers.Lambda(lambda x: tf.reduce_mean(x, axis=1, keepdims=True), name='output3')(tf.concat([l1, l2], axis=1))

model = tf.keras.Model(inputs, [output1,output2,output3])

model.compile(
        optimizer=tf.keras.optimizers.Adam(),
        loss= tf.keras.losses.mse,
        metrics=tf.keras.metrics.RootMeanSquaredError(name="rmse"))
history = model.fit(x_train,{"output1": n1_y_train, "output2": n2_y_train, "output3": n3_y_train},
validation_data = (x_test,{"output1": n1_y_test, "output2": n2_y_test, "output3": n3_y_test}),
verbose=2,
epochs=100,
batch_size=2)