具有二进制(圆形)和张量流后端的Keras自定义丢失函数

时间:2018-01-20 12:17:10

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

我目前正在尝试使用二进制结果实现自定义丢失函数(精度),但Tensorflow后端拒绝使用循环函数,这必须用于生成' 0'或者' 1'。

据我所研究,这是因为Tensorflow将该轮的渐变定义为None,而损失函数不能返回None。

我目前已实施此自定义损失,以尽可能接近创建' 0'或者' 1'在R Keras界面。

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())))
}

注意&#34; sigmoid&#34; :K $最大值(0,K $最小值(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())))
}

有些人在没有使用round来生成损失函数中的二进制结果的情况下有另一种实现吗?

PD:在自定义指标功能中,允许回合

2 个答案:

答案 0 :(得分:1)

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

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

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

你当然可以通过修改Keras或TensorFlow的本地副本来实现这一目标,但没有任何好处可以来自它。

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

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

答案 1 :(得分:1)

正如您所注意到自定义丢失函数需要基于已定义渐变的函数(为了最小化损失函数),这是对于简单的指标不是必需的。某些函数如“round”和“sign”很难在损失函数中使用,因为它们的渐变始终为null或无穷大,这对最小化没有帮助。这可能是为什么他们的渐变未定义,默认情况下。

然后,您有两个选择:

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

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

  

max_gradient = 100

     

K $最大值(0,K $最小值(1,0.5 *(1+(max_gradient * y_pos)/(1+ max_gradient * abs(y_pos)))))

max_gradient系数可用于使您的边缘更加清晰,大约0.5。它将最大梯度定义为0.5。