首页 > 解决方案 > Keras 自定义损失:a * MAE + (1-a) * 常量

问题描述

我正在尝试在 Keras 中实现一个相当简单的自定义损失函数。

我试图让网络预测一个错误的输入情况(即它没有机会预测正确的输出)以及正确的输出。为了尝试做到这一点,我使用了一个损失函数,它允许网络“选择”一个恒定损失 (8) 而不是当前损失(由 MAE 确定)。

 loss = quality * output + (1-quality) * 8

质量是从 sigmoid 输出的,所以在 [0,1]

我将如何在 Keras 中正确设计这样的损失函数?

具体来说,在基本情况下,网络会获得多个输出预测,以及已知或认为与预测质量相关的指标。(小型)网络的作用是使用这些指标来确定在对这些不同的预测进行平均时要给出的权重。这工作得很好。

但是,在某些情况下(例如 5-10%),输入数据非常糟糕,以至于所有预测器都会出错。在那种情况下,我想输出'?给用户而不是错误的答案。

我的代码抱怨 1 个数组与 2 个数组(大概,y_true 和 y_pred 的数量相同,但我没有这些)。

model = Model(inputs=[ain, in1, in2, in3, in4, in5, x], outputs=[pred,qual])
model.compile(loss=quality_loss, optimizer='adam', metrics=['mae'])
model.fit([acc, hrmet0, hrmet1, hrmet2, hrmet3, hrmet4, hrs], ref, epochs=50, batch_size=5000, verbose=2, shuffle=True)

似乎有两个输出导致每个输出独立调用损失函数。

ValueError: Error when checking model target: the list of Numpy arrays that you
are passing to your model is not the size the model expected. Expected to see 2
array(s), but instead got the following list of 1 arrays:

这是通过传递一个串联数组来解决的。

def quality_loss(y_true, y_pred):
  qual = y_pred[:,0]
  hr   = y_pred[:,1]
  const = 8

  return qual * mean_absolute_error(y_true,hr) + (1 - qual) * const

def my_mae(y_true,y_pred):
  return  mean_absolute_error(y_true,y_pred[:,1])

model = Model(inputs=[xin, in1, in2, in3, in4, in5, hr],     outputs=concatenate([qual, pred_hr]))
model.compile(loss=quality_loss, optimizer='adam', metrics=[my_mae])

网络代码:

xin = Input(shape=(1,))

in1 = Input(shape=(4,))
net1 = Dense(3,activation='tanh')( Dense(6,activation='tanh')(in1) )
in2 = Input(shape=(4,))
net2 = Dense(3,activation='tanh')( Dense(6,activation='tanh')(in2) )
in3 = Input(shape=(4,))
net3 = Dense(3,activation='tanh')( Dense(6,activation='tanh')(in3) )
in4 = Input(shape=(4,))
net4 = Dense(3,activation='tanh')( Dense(6,activation='tanh')(in4) )
in5 = Input(shape=(4,))
net5 = Dense(3,activation='tanh')( Dense(6,activation='tanh')(in5) )

smweights = Dense(5, activation='softmax')( concatenate([xin, net1, net2, net3, net4, net5]) ) 
qual = Dense(1, activation='sigmoid')( Dense(3, activation='tanh')( concatenate([xin, net1, net2, net3, net4, net5]) ) ) 

x = Input(shape=(5,))
pred = dot([x, smweights], axes=1) 

这会运行,但会收敛到 loss = const 和 mae > 25(而这里的简单 mae 损失很容易达到 3-4)。损失函数仍然不太对劲。由于损失函数中 y_true/y_pred 上的形状给出了 (?),因此很难准确跟踪传递的内容。

标签: pythonkeras

解决方案


这个问题实际上不是由您的自定义损失函数引起的,而是由其他原因引起的:问题的出现是因为您调用 fit 函数的方式。当你定义模型时,你给它7输入和2输出:

model = Model(inputs=[ain, in1, in2, in3, in4, in5, x], outputs=[pred,qual])

当您最终调用该fit函数时,您会给出一个列表7数组作为网络的输入,但只有1目标输出值称为ref

model.fit([acc, hrmet0, hrmet1, hrmet2, hrmet3, hrmet4, hrs], ref, ...)

这行不通。您必须为fit函数提供与模型定义中声明的相同数量的输入和输出。

编辑:我认为您的方法存在一些概念问题:您实际上打算如何定义预测的质量?你为什么认为,添加一个应该判断网络预测质量的网络分支实际上有助于训练它?网络将收敛到损失函数的局部最小值。你的损失函数越漂亮,它就越有可能不会真正收敛到你真正希望它处于的状态,而是收敛到其他一些局部而非全局最小值。您可以尝试使用不同的优化器和学习率 - 也许这有助于您的训练。


推荐阅读