【问题标题】:Keras custom loss function with binary (round) with tensorflow backendKeras 自定义损失函数,带有 tensorflow 后端的二进制(圆形)
【发布时间】:2018-01-20 12:17:09
【问题描述】:

我目前正在尝试实现具有二进制结果的自定义损失函数(精度),但 Tensorflow 后端拒绝使用生成“0”或“1”所必需的圆形函数。

据我调查,这是因为 Tensorflow 将轮次的梯度定义为 None 并且损失函数不能返回 None。

我目前已实现此自定义损失,以在 R Keras 界面中创建尽可能接近的“0”或“1”。

precision_loss<-function(y_true,y_pred){
  y_pred_pos = K$clip(y_pred, 0, 1)
  #Custom sigmoid to generate '0' '1'
  y_pred_pos =  K$maximum(0,K$minimum(1,(y_pred_pos+0.0625)/0.125))
  y_pred_neg = 1 - y_pred_pos
  y_pos = K$clip(y_true, 0, 1)
  #Custom sigmoid to generate '0' '1'
  y_pos =  K$maximum(0,K$minimum(1,(y_pos+0.0625)/0.125))
  y_neg = 1 - y_pos
  #Generate confusion matrix counts
  tp = K$sum(y_pos*y_pred_pos)
  tn = K$sum(y_neg*y_pred_neg)
  fp = K$sum(y_neg*y_pred_pos)
  fn = K$sum(y_pos*y_pred_neg)
  return(1-(tp/(tp+fp+K$epsilon())))
}

注意“sigmoid”:K$maximum(0,K$minimum(1,(y_pos+0.0625)/0.125))

我想要实现的是一个解决方法:

precision_loss<-function(y_true, y_pred){
  y_pred_pos = K$round(K$clip(y_pred, 0, 1))
  y_pred_neg = 1 - y_pred_pos
  y_pos = K$round(K$clip(y_true, 0, 1))
  y_neg = 1 - y_pos
  #Generate confusion matrix counts
  tp = K$sum(K$clip(y_pos * y_pred_pos,0,1))
  tn = K$sum(K$clip(y_neg * y_pred_neg,0,1))
  fp = K$sum(K$clip(y_neg * y_pred_pos,0,1))
  fn = K$sum(K$clip(y_pos * y_pred_neg,0,1))
  return(1-(tp/(tp+fp+K$epsilon())))
}

你们中的一些人有另一种实现,而不使用轮来在损失函数中生成二元结果?

PD:在自定义指标函数中允许轮次

【问题讨论】:

    标签: tensorflow machine-learning deep-learning keras loss


    【解决方案1】:

    为了构建二元损失函数,仅构建自定义损失函数本身是不够的。您还必须预先定义渐变。

    您的高维损失函数在某些点上为零,而在所有其他点上为零。对于该空间中的所有 非连续 点,不可能解析地计算梯度(即这些点甚至不存在梯度的概念),因此您只需定义一。对于这个空间中的所有 连续 点(例如,一个所有损失值为 1 的开放集),梯度会存在,但它会为零,因此您还必须预先定义梯度值,否则你的权重根本不会移动。

    这意味着无论哪种方式,您都必须为图中的特定节点(损失函数节点)定义自己的自定义“梯度”计算函数,以替换 Keras(即 TensorFlow 的)自动微分引擎。

    您当然可以通过修改 Keras 或 TensorFlow 的本地副本来实现这一点,但它不会带来任何好处。

    此外,即使您设法做到了,请考虑以下问题:如果您的损失函数仅返回 0 或 1,这意味着它只能区分两种状态:模型的预测要么 100% 正确(0 损失),要么不是 100% 正确(1 次失败)。对于所有非 100% 的情况,梯度的大小必须相同。那是理想的财产吗?

    您的准二元 sigmoid 解决方案有同样的问题:梯度几乎在所有地方都几乎为零,并且在它不会几乎为零的少数点上,它几乎是无穷大。如果您尝试使用该损失函数训练模型,它不会学到任何东西。

    【讨论】:

      【解决方案2】:

      如您所见,自定义损失函数需要基于定义了梯度的函数(以最小化损失函数),即对于简单的指标来说不是必需的。像 “round” 和 “sign” 这样的函数很难在损失函数中使用,因为它们的梯度要么一直为空,要么是无限的,这对最小化没有帮助。这可能是默认情况下没有定义它们的渐变的原因。

      那么,你有两个选择:

      • 选项 1:您使用 round 函数,但您需要为 round 添加自定义渐变,以在后端替换它。
      • 选项 2:您定义另一个损失函数而不使用 round

      您选择了选项 2,这是我认为的最佳选项。但是你的“sigmoid”是非常线性的,所以可能不是你的“round”函数的一个很好的近似。你可以使用一个实际的 sigmoid,它由于使用指数而速度较慢,但​​你可以通过修改后的 softsign 获得类似的结果:

      max_gradient=100

      K$maximum(0,K$minimum(1,0.5*(1+(max_gradient*y_pos)/(1+ max_gradient*abs(y_pos)))))

      max_gradient 系数可用于使您的边缘更锐利,大约为 0.5。它定义了 0.5 处的最大梯度。

      【讨论】:

        猜你喜欢
        • 2017-04-21
        • 2017-12-01
        • 2018-12-26
        • 2018-08-06
        • 2018-10-28
        • 2017-12-29
        • 1970-01-01
        • 2020-10-21
        • 1970-01-01
        相关资源
        最近更新 更多