如何:忽略 NA 值(或以其他方式掩盖损失)的 TensorFlow-Probability 自定义损失

How to: TensorFlow-Probability custom loss that ignores NA values (or otherwise masks loss)

我寻求在 TensorFlow-Probability 中实现一个屏蔽损失函数,它可以忽略标签中的 NA。

对于常规张量来说,这是一项老掉牙的任务。我找不到分发示例。

我的分布大小(批次、时间步长、输出)(512、251 天,1 到 8 个时间序列)

示例中给出的传统损失函数是使用分布的对数概率。

neg_log_likelihood <- function (x, rv_x) {
  -1*(rv_x %>% tfd_log_prob(x))
}

当我用零替换 NA 时,模型训练良好并收敛。当我离开 NA 时,它会按预期产生 NaN 损失。

我已经尝试了 tf$where 的许多不同排列,以用 0 替换损失,用 0 替换标签,等等。在每一种情况下,模型都会停止训练并且损失保持在某个常数附近。即使标签中只有一个 NA 也是如此。

neg_log_likelihood_missing <-  function (x, rv_x) {
  
  loss =     -1*(  rv_x %>% tfd_log_prob(x) ) 
  
  loss_nonan = tf$where( tf$math$is_finite(x) , loss, 0  )
  
  return( 
    loss_nonan
  )
}

我在这里使用 R 是偶然的,python 中的任何示例或其他我都可以翻译。如果有正确的方法可以使损失正确反向传播,我将不胜感激。

如果您使用的是基于梯度的推理,您可能需要“双重位置”技巧。

虽然这会为您提供正确的 y 值:

y = computation(x)
tf.where(is_nan(y), 0, y)

...tf.where 的导数仍然可以有 nan.

改为:

safe_x = tf.where(is_unsafe(x), some_safe_x, x)
y = computation(safe_x)
tf.where(is_unsafe(x), 0, y)

...得到一个保险箱 y 和一个保险箱 dy/dx.

对于你正在考虑的情况,也许写:

class MyMaskedDist(tfd.Distribution):
  ...
  def _log_prob(self, x):
    safe_x = tf.where(tf.is_nan(x), self.mode(), x)
    lp = compute_log_prob(safe_x)
    lp = tf.where(tf.is_nan(x), tf.zeros([], lp.dtype), lp)
    return lp