Keras中某些重叠子模型上的多个损失函数

问题描述

我在Keras中有一个模型,我想使用两个损失函数。该模型由一个自动编码器和一个分类器组成。我想使用一个损失函数来确保自动编码器安装得相当好(例如,可以是mse),而另一个损失函数可以评估分类器(例如,categorical_crossentropy)。我想拟合模型并使用损失函数,该函数将是两个损失函数的线性组合。

# loss functions
def ae_mse_loss(x_true,x_pred):
    ae_loss = K.mean(K.square(x_true - x_pred),axis=1)
    return ae_loss

def clf_loss(y_true,y_pred):
    return K.sum(K.categorical_crossentropy(y_true,y_pred),axis=-1)

def combined_loss(y_true,y_pred):
    ???
    return ae_loss + w1*clf_loss

其中w1是定义最终合并损失中“ clf_loss的重要性”的权重。


# autoencoder
ae_in_layer = Input(shape=in_dim,name='ae_in_layer')
ae_interm_layer1 = Dense(interm_dim,activation='relu',name='ae_interm_layer1')(ae_in_layer)
ae_mid_layer = Dense(latent_dim,name='ae_mid_layer')(ae_interm_layer1)
ae_interm_layer2 = Dense(interm_dim,name='ae_interm_layer2')(ae_mid_layer)
ae_out_layer = Dense(in_dim,activation='linear',name='ae_out_layer')(ae_interm_layer2)

ae_model=Model(ae_input_layer,ae_out_layer)
ae_model.compile(optimizer='adam',loss = ae_mse_loss)

# classifier
clf_in_layer = Dense(interm_dim,activation='sigmoid',name='clf_in_layer')(ae_out_layer)
clf_out_layer = Dense(3,activation='softmax',name='clf_out_layer')(clf_in_layer)

clf_model = Model(clf_in_layer,clf_out_layer)
clf_model.compile(optimizer='adam',loss = combined_loss,metrics = [ae_mse_loss,clf_loss])

我不确定的是如何在两个损失函数中区分y_true和y_pred(因为它们是指模型中不同阶段的真实数据和预测数据)。我的想法是这样的(我不确定如何实现它,因为显然我只需要传递一组参数y_true和y_pred):

def combined_loss(y_true,y_pred):
    ae_loss = ae_mse_loss(x_true_ae,x_pred_ae)
    clf_loss = clf_loss(y_true_clf,y_pred_clf)
    return ae_loss + w1*clf_loss

我可以将这个问题定义为两个单独的模型,并分别训练每个模型,但是如果可能的话,我可以一次完成所有操作(因为这将同时优化两个问题),所以我真的很希望。我意识到,这个模型没有多大意义,但是它展示了我试图以一种简单方式解决的(更为复杂的)问题。

任何建议将不胜感激。

解决方法

您所需要的只是在本地keras中提供

您可以使用loss_weights参数自动合并多个损失

在下面的示例中,我尝试重现您的示例,其中我将回归任务的mse损失和分类任务的categorical_crossentropy合并在一起

in_dim = 10
interm_dim = 64
latent_dim = 32
n_class = 3
n_sample = 100

X = np.random.uniform(0,1,(n_sample,in_dim))
y = tf.keras.utils.to_categorical(np.random.randint(0,n_class,n_sample))

# autoencoder
ae_in_layer = Input(shape=in_dim,name='ae_in_layer')
ae_interm_layer1 = Dense(interm_dim,activation='relu',name='ae_interm_layer1')(ae_in_layer)
ae_mid_layer = Dense(latent_dim,name='ae_mid_layer')(ae_interm_layer1)
ae_interm_layer2 = Dense(interm_dim,name='ae_interm_layer2')(ae_mid_layer)
ae_out_layer = Dense(in_dim,activation='linear',name='ae_out_layer')(ae_interm_layer2)

# classifier
clf_in_layer = Dense(interm_dim,activation='sigmoid',name='clf_in_layer')(ae_out_layer)
clf_out_layer = Dense(n_class,activation='softmax',name='clf_out_layer')(clf_in_layer)

model = Model(ae_in_layer,[ae_out_layer,clf_out_layer])
model.compile(optimizer='adam',loss = {'ae_out_layer':'mse','clf_out_layer':'categorical_crossentropy'},loss_weights = {'ae_out_layer':1.,'clf_out_layer':0.5})

model.fit(X,[X,y],epochs=10)

在这种情况下,loss1*ae_out_layer_loss + 0.5*clf_out_layer_loss的结果