Keras 中的多个输出
Posted
技术标签:
【中文标题】Keras 中的多个输出【英文标题】:Multiple outputs in Keras 【发布时间】:2017-10-17 15:09:20 【问题描述】:当给定一个预测变量向量时,我有一个处理预测两个输出的问题。
假设一个预测向量看起来像x1, y1, att1, att2, ..., attn
,其中x1, y1
是坐标,att's
是附加到x1, y1
坐标出现的其他属性。基于这个预测器集,我想预测x2, y2
。这是一个时间序列问题,我正在尝试使用多重回归来解决。
我的问题是如何设置 keras,它可以在最后一层给我 2 个输出。
【问题讨论】:
【参考方案1】:from keras.models import Model
from keras.layers import *
#inp is a "tensor", that can be passed when calling other layers to produce an output
inp = Input((10,)) #supposing you have ten numeric values as input
#here, SomeLayer() is defining a layer,
#and calling it with (inp) produces the output tensor x
x = SomeLayer(blablabla)(inp)
x = SomeOtherLayer(blablabla)(x) #here, I just replace x, because this intermediate output is not interesting to keep
#here, I want to keep the two different outputs for defining the model
#notice that both left and right are called with the same input x, creating a fork
out1 = LeftSideLastLayer(balbalba)(x)
out2 = RightSideLastLayer(banblabala)(x)
#here, you define which path you will follow in the graph you've drawn with layers
#notice the two outputs passed in a list, telling the model I want it to have two outputs.
model = Model(inp, [out1,out2])
model.compile(optimizer = ...., loss = ....) #loss can be one for both sides or a list with different loss functions for out1 and out2
model.fit(inputData,[outputYLeft, outputYRight], epochs=..., batch_size=...)
【讨论】:
所以如果我理解正确,那么你的意思是:InputShape = (10, )
model_1 = Sequential() model_1.add(Dense(250, activation='tanh', input_shape=(InputShape))) model_1.add(Dense(2, activation='relu')) model_1.compile(optimizer='adam', loss='mse', metrics=['accuracy']) model_1.fit(predictors, targets, epochs=whatever, ....)
。我的问题是,这与您的问题有何不同,您只指定两个输出。
在我的回答中添加了 cmets :) -- 您不能使用顺序模型创建分支,这根本不可能。
@Daniel 嗨,Daniel,你能详细说明一下吗?我正在寻找的是有一个尝试预测两个不同事物的网络,所以我正在想象在倒数第二层发生的一个分支,该分支馈送到两个不同的 softmax 层,然后我连接这两个层的结果,然后反向传播对此。这在 keras 中是不可能的吗?
如果您知道双方的真实值,则无需将它们连接起来。该模型将自动完成所有操作。 (我能想到的连接两个分支的唯一原因是:1 - 你的真实数据已经连接;2 - 你想添加更多的层作为输入)。【参考方案2】:
您可以使用以下方法制作具有多个输出的模型
函数式 API
通过子类化tf.keras.Model
。
以下是 Iris 数据集上使用功能 API 的双重输出(回归和分类)的示例:
from sklearn.datasets import load_iris
from tensorflow.keras.layers import Dense
from tensorflow.keras import Input, Model
import tensorflow as tf
data, target = load_iris(return_X_y=True)
X = data[:, (0, 1, 2)]
Y = data[:, 3]
Z = target
inputs = Input(shape=(3,), name='input')
x = Dense(16, activation='relu', name='16')(inputs)
x = Dense(32, activation='relu', name='32')(x)
output1 = Dense(1, name='cont_out')(x)
output2 = Dense(3, activation='softmax', name='cat_out')(x)
model = Model(inputs=inputs, outputs=[output1, output2])
model.compile(loss='cont_out': 'mean_absolute_error',
'cat_out': 'sparse_categorical_crossentropy',
optimizer='adam',
metrics='cat_out': tf.metrics.SparseCategoricalAccuracy(name='acc'))
history = model.fit(X, 'cont_out': Y, 'cat_out': Z, epochs=10, batch_size=8)
这是一个简化版:
from sklearn.datasets import load_iris
from tensorflow.keras.layers import Dense
from tensorflow.keras import Input, Model
data, target = load_iris(return_X_y=True)
X = data[:, (0, 1, 2)]
Y = data[:, 3]
Z = target
inputs = Input(shape=(3,))
x = Dense(16, activation='relu')(inputs)
x = Dense(32, activation='relu')(x)
output1 = Dense(1)(x)
output2 = Dense(3, activation='softmax')(x)
model = Model(inputs=inputs, outputs=[output1, output2])
model.compile(loss=['mae', 'sparse_categorical_crossentropy'], optimizer='adam')
history = model.fit(X, [Y, Z], epochs=10, batch_size=8)
这是相同的示例,子类化 tf.keras.Model
并使用自定义训练循环:
import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras import Model
from sklearn.datasets import load_iris
tf.keras.backend.set_floatx('float64')
iris, target = load_iris(return_X_y=True)
X = iris[:, :3]
y = iris[:, 3]
z = target
ds = tf.data.Dataset.from_tensor_slices((X, y, z)).shuffle(150).batch(8)
class MyModel(Model):
def __init__(self):
super(MyModel, self).__init__()
self.d0 = Dense(16, activation='relu')
self.d1 = Dense(32, activation='relu')
self.d2 = Dense(1)
self.d3 = Dense(3, activation='softmax')
def call(self, x, training=None, **kwargs):
x = self.d0(x)
x = self.d1(x)
a = self.d2(x)
b = self.d3(x)
return a, b
model = MyModel()
loss_obj_reg = tf.keras.losses.MeanAbsoluteError()
loss_obj_cat = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)
loss_reg = tf.keras.metrics.Mean(name='regression loss')
loss_cat = tf.keras.metrics.Mean(name='categorical loss')
error_reg = tf.keras.metrics.MeanAbsoluteError()
error_cat = tf.keras.metrics.SparseCategoricalAccuracy()
@tf.function
def train_step(inputs, y_reg, y_cat):
with tf.GradientTape() as tape:
pred_reg, pred_cat = model(inputs)
reg_loss = loss_obj_reg(y_reg, pred_reg)
cat_loss = loss_obj_cat(y_cat, pred_cat)
gradients = tape.gradient([reg_loss, cat_loss], model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
loss_reg(reg_loss)
loss_cat(cat_loss)
error_reg(y_reg, pred_reg)
error_cat(y_cat, pred_cat)
for epoch in range(50):
for xx, yy, zz in ds:
train_step(xx, yy, zz)
template = 'Epoch :>2, SCCE: :>5.2f,' \
' MAE: :>4.2f, SAcc: :>5.1%'
print(template.format(epoch+1,
loss_cat.result(),
error_reg.result(),
error_cat.result()))
loss_reg.reset_states()
loss_cat.reset_states()
error_reg.reset_states()
error_cat.reset_states()
【讨论】:
我只是好奇双输入有什么好处?有两个独立的模型(分类和回归)会更好吗?谢谢.. 好处是神经网络可以学习数据中对这两个任务都有用的结构。所以更少的参数 我想我只是想看看这与两个单独的任务相比会如何执行。我会尝试一下。感谢您的代码。 网络如何解释平均绝对误差可能远小于交叉熵这一事实,特别是如果输出归一化为 0-1 范围(MAE 1)?以上是关于Keras 中的多个输出的主要内容,如果未能解决你的问题,请参考以下文章
带有 LSTM 单元的 Keras RNN 用于基于多个输入时间序列预测多个输出时间序列
在 Keras 自定义层中连接多个形状为 (None, m) 的 LSTM 输出
使用 Keras LSTM 进行多步提前时间序列预测的多个输出