在 Keras 中实现自定义 objective 函数

Implementing a custom objective function in Keras

我正在尝试实现自定义 Keras objective 函数:

in 'Direct Intrinsics: Learning Albedo-Shading Decomposition by Convolutional Regression', Narihira et al.

这是上一张图片中方程 (4)(6) 的总和。 Y*是ground truth,Y是预测图,y = Y* - Y

这是我的代码:

def custom_objective(y_true, y_pred):
  #Eq. (4) Scale invariant L2 loss
  y = y_true - y_pred
  h = 0.5 # lambda
  term1 = K.mean(K.sum(K.square(y)))
  term2 = K.square(K.mean(K.sum(y)))
  sca = term1-h*term2    
  #Eq. (6) Gradient L2 loss
  gra = K.mean(K.sum((K.square(K.gradients(K.sum(y[:,1]), y)) + K.square(K.gradients(K.sum(y[1,:]), y)))))
  return (sca + gra)

但是,我怀疑方程(6)没有正确实现,因为结果不好。我计算得对吗?

谢谢!

编辑:

我正在尝试近似 (6) 与 Prewitt 过滤器的卷积。当我的输入是一大块图像时它起作用,即 y[batch_size, channels, row, cols],但不适用于 y_truey_pred(类型为 TensorType(float32, 4D))。

我的代码:

def cconv(image, g_kernel, batch_size):
  g_kernel = theano.shared(g_kernel)
  M = T.dtensor3()
  conv = theano.function(
      inputs=[M],
      outputs=conv2d(M, g_kernel, border_mode='full'),
  )
  accum = 0
  for curr_batch in range (batch_size):
      accum = accum + conv(image[curr_batch])
  return accum/batch_size


def gradient_loss(y_true, y_pred):
  y = y_true - y_pred

  batch_size = 40

  # Direction i
  pw_x = np.array([[-1,0,1],[-1,0,1],[-1,0,1]]).astype(np.float64)
  g_x = cconv(y, pw_x, batch_size)

  # Direction j
  pw_y = np.array([[-1,-1,-1],[0,0,0],[1,1,1]]).astype(np.float64)
  g_y = cconv(y, pw_y, batch_size)

  gra_l2_loss = K.mean(K.square(g_x) + K.square(g_y))

  return (gra_l2_loss)

崩溃产生于:

    accum = accum + conv(image[curr_batch])

...错误描述如下:

*** TypeError: ('Bad input argument to theano function with name "custom_models.py:836" at index 0 (0-based)', 'Expected an array-like object, but found a Variable: maybe you are trying to call a function on a (possibly shared) variable instead of a numeric array?')

如何将 y (y_true - y_pred) 用作 numpy 数组,或者如何解决这个问题?

SIL2

term1 = K.mean(K.square(y))
term2 = K.square(K.mean(y))
[...]

代码中的一个错误是,当您在方程式中看到 (1/n * sum()) 时,它是一个 均值 。不是总和的平均值。

渐变

在阅读了您的评论并进行了更多思考后,我认为渐变存在混淆。至少我糊涂了。

渐变符号有两种解读方式:

  1. gradient of a vector 其中 y 应该根据模型的参数(通常是神经网络的权重)进行区分。在之前的编辑中,我开始朝这个方向写作,因为这是用于训练模型的那种方法(例如梯度下降)。但我想我错了。
  2. 正如您在评论中提到的,图片中的像素强度梯度。每个像素与其相邻像素在每个方向上的差异。在这种情况下,我想你必须将你给出的例子翻译成 Keras。

综上所述,K.gradients()numpy.gradient()的用法不一样。因为 numpy 隐含地将 (i, j)(行和列索引)视为两个输入变量,而当您将 2D 图像馈送到神经网络时,每个像素 一个输入多变的。希望我说清楚了。