如何从Keras的自定义损失函数中获得结果?

7
我希望在Python中实现一个自定义的损失函数,并且它应该像下面的伪代码一样工作:
aux = | Real - Prediction | / Prediction
errors = []
if aux <= 0.1:
 errors.append(0)
elif aux > 0.1 & <= 0.15:
 errors.append(5/3)
elif aux > 0.15 & <= 0.2:
 errors.append(5)
else:
 errors.append(2000)
return sum(errors)

我开始这样定义度量衡:

def custom_metric(y_true,y_pred):
    # y_true:
    res = K.abs((y_true-y_pred) / y_pred, axis = 1)
    ....

但是我不知道如何获取ifelse的结果值。另外,我想知道函数应该返回什么。

谢谢

3个回答

6

我想知道该函数需要返回什么内容。

在编译时可以传递自定义指标。

该函数需要将(y_true, y_pred)作为参数,并返回单个张量值。

但我不知道如何获取 if 和 else 的 res 值。

可以从result_metric函数中返回result值。

def custom_metric(y_true,y_pred):
     result = K.abs((y_true-y_pred) / y_pred, axis = 1)
     return result

第二步是使用一个keras回调函数来计算错误的总和。
可以定义并将回调函数传递给fit方法。
history = CustomLossHistory()
model.fit(callbacks = [history])

最后一步是创建CustomLossHistory类,以便找出您期望的错误列表的sumCustomLossHistory将从keras.callbacks.Callback继承一些默认方法。
  • on_epoch_begin:在每个时期的开始调用。
  • on_epoch_end:在每个时期的结束调用。
  • on_batch_begin:在每个批次的开始调用。
  • on_batch_end:在每个批次的结束调用。
  • on_train_begin:在模型训练开始时调用。
  • on_train_end:在模型训练结束时调用。
您可以在Keras文档中阅读更多内容。
但对于这个示例,我们只需要on_train_beginon_batch_end方法。 实现
class LossHistory(keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        self.errors= []

    def on_batch_end(self, batch, logs={}):
         loss = logs.get('loss')
         self.errors.append(self.loss_mapper(loss))

    def loss_mapper(self, loss):
         if loss <= 0.1:
             return 0
         elif loss > 0.1 & loss <= 0.15:
             return 5/3
         elif loss > 0.15 & loss <= 0.2:
             return 5
         else:
             return 2000

在您的模型训练完成后,您可以使用以下语句访问您的错误
errors = history.errors

@Aceconhielo,是的,神经网络尝试使用“优化器”来最小化这个总和。 - Mihai Alexandru-Ionut
@Aceconhielo,你可以尝试使用更多的“epochs”,因为0.15是一个较低的损失值,只有在使用许多“epochs”并且模型具有非常好的学习能力时才能达到。 - Mihai Alexandru-Ionut
@Mihai Alexandru-Ionut 好的,我的目标是计算成本函数。如果我理解你的回答正确的话,成本函数将与LossHistory相同,但将on_batch_end的名称更改为on_epoch_end?这样做的问题是当我训练网络时,损失值会变成nan。 - Aceconhielo
在您的自定义度量函数中包含 print(result)。您是否收到了预期值? - Mihai Alexandru-Ionut
1
@Mihai Alexandru-Ionut 不用在意,问题已经解决了。但是我还有一个问题,如果你不介意的话。我想预测的值在0到1之间,但是我的预测输出有时候小于0或者大于1。你知道怎么解决吗? - Aceconhielo
显示剩余10条评论

1
我会冒险说这不起作用,因为它不可微分。损失函数需要连续可微才能通过那里传播梯度。
如果你想让它起作用,你需要找到一种避免不连续的方法。例如,你可以尝试对你的4个离散值进行加权平均,其中权重强烈偏向最近的值。

我的错。我忘了说最后我想把所有的错误都加起来。我修改了问题。 - Aceconhielo

0

直接将内容附加到self上对我没有起作用,相反,将内容附加到self的params字典中才能完成任务。回答op,应该是self.params['error'] = [],然后根据需要向数组中添加内容。

class CustomCallback(tf.keras.callbacks.Callback):
     
     def on_train_begin(self, logs=None):
          self.params['error'] = []

     def on_epoch_end(self, epochs, logs=None):
          #do something with self.params['error']

history = model.fit(callbacks = [CustomCallback()])

#When train ends

error = history.params['error']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接