用于360度预测的keras损失函数

kmh*_*kmh 6 conv-neural-network keras tensorflow

我正在尝试使用keras / tensorflow预测方位角。y_true的范围是0-359,但是我需要一个损失函数来处理围绕该范围且超出该范围的预测。不幸的是,当我尝试任何类型的模块化除法tf.mod()或时%,我得到一个错误...

LookupError: No gradient defined for operation 'FloorMod' (op type: FloorMod)
Run Code Online (Sandbox Code Playgroud)

所以我想我已经通过以下方法解决了这个问题...

def mean_squared_error_360(y_true, y_pred):
  delta = K.minimum(K.minimum(K.abs(y_pred - y_true),
                              K.abs(y_pred - (360+y_true))),
                              K.abs(y_true - (360+y_pred)))
  return K.mean(K.square(delta), axis=-1)

def rmse_360(y_true, y_pred):
  return K.sqrt(mean_squared_error_360(y_true, y_pred))


model.compile(loss=mean_squared_error_360,
              optimizer=rmsprop(lr=0.0001),
              metrics=[rmse_360])
Run Code Online (Sandbox Code Playgroud)

这可以处理以下几种极端情况...我没有遇到<0的预测,所以我没有解决。

y =   1  y_pred = 361  err = 0
y = 359  y_pred =   1  err = 2
y = 359  y_pred = 361  err = 2
Run Code Online (Sandbox Code Playgroud)

问题

  • 这感觉笨拙;有没有更聪明的解决方案?
  • 凭直觉,我认为使用mean_squared_error和root_mean_squared_error之间的结果没有区别,因为损失...梯度会有所不同,但相同的最佳权重将同时解决这两个问题,对吗?有什么理由选择另一个吗?我猜mse比rmse稍微简单些,但这应该是微不足道的。我已经尝试过两者,并且使用rmse的“感觉”像比mse更有序地下降...那些平方误差的大小是否会使它跳得更多?

提前致谢。

编辑

无论出于什么原因……我最初的女士似乎都适合训练集,但是验证集在各个时期似乎都是很嘈杂的,经过几个时期后并没有任何实质性的改进。rmse似乎是有序下降的。。。直到改善了几十个纪元之后,损失才降到了inf。我可能会遇到比损失函数更大的问题。

编辑2-在下面添加我的实现@Patwie答案

啊!当然!!不幸的是,我正在使用tf v1.0,它似乎没有tf.atan2()。奇怪的是,我在tf存储库中找不到atan2实现,但是我认为asos-ben在问题6095中的建议可以解决问题。看到这里:https : //github.com/tensorflow/tensorflow/issues/6095

def atan2(x, y, epsilon=1.0e-12):
  x = tf.where(tf.equal(x, 0.0), x+epsilon, x)
  y = tf.where(tf.equal(y, 0.0), y+epsilon, y)    
  angle = tf.where(tf.greater(x,0.0), tf.atan(y/x), tf.zeros_like(x))
  angle = tf.where(tf.logical_and(tf.less(x,0.0),  tf.greater_equal(y,0.0)), tf.atan(y/x) + np.pi, angle)
  angle = tf.where(tf.logical_and(tf.less(x,0.0),  tf.less(y,0.0)), tf.atan(y/x) - np.pi, angle)
  angle = tf.where(tf.logical_and(tf.equal(x,0.0), tf.greater(y,0.0)), 0.5*np.pi * tf.ones_like(x), angle)
  angle = tf.where(tf.logical_and(tf.equal(x,0.0), tf.less(y,0.0)), -0.5*np.pi * tf.ones_like(x), angle)
  angle = tf.where(tf.logical_and(tf.equal(x,0.0), tf.equal(y,0.0)), tf.zeros_like(x), angle)
  return angle

# y in radians
def rmse_360_2(y_true, y_pred):
  return K.mean(K.abs(atan2(K.sin(y_true - y_pred), K.cos(y_true - y_pred))))
Run Code Online (Sandbox Code Playgroud)

在测试运行中只有大约7个纪元,但这似乎很有希望。

Pat*_*wie 7

将我的评论转换为答案。给定两个角a(gt),b(预测)作为弧度,则得到的角度差为

tf.atan2(tf.sin(a - b), tf.cos(a - b))
Run Code Online (Sandbox Code Playgroud)

根据定义tf.atan2,在关闭间隔[-pi, +pi](即[-180 degrees, +180 degrees])内自动给出差值。

因此,您可以使用

tf.reduce_mean(tf.abs(tf.atan2(tf.sin(a - b), tf.cos(a - b))))
Run Code Online (Sandbox Code Playgroud)

我认为Keras理解此TensorFlow代码。

  • 此解决方案效果很好,但需要说明的是,atan2 返回 [-pi, pi] 弧度区间的最小差异。 (2认同)