如何在Tensorflow中使用Python制作自定义损失函数+渐变?

时间:2019-09-13 10:42:08

标签: python tensorflow keras gradient loss-function

这通常是关于使用tf.numpy_function编写自定义损失函数。自定义损失函数的梯度也必须手动提供。

假定编写了带有附加输入参数的自定义损失函数。

def custom_loss(self, targetPosition):
    def loss(y_true, y_pred):
        loss_ = tf.numpy_function(self.forAllWrapped, [y_pred, targetPosition], tf.float32)
        return loss_;
    return loss

其中损失函数写在tf.numpy_function包装器中,该包装器将张量值作为Numpy数组获取,并通过GRPC发送给一些C#代码以计算损失。

def forAllWrapped(self, y_pred, targetPosition):
    result= np.empty((0,targetPosition.shape[1]), np.float)
    i=0
    numFKs = y_pred.shape[0]
    while i < numFKs :
        res_ =sres_=GET-INDIVIDUAL-LOSS-FROM-GRPC-METHOD(y_pred[i,],targetPosition[i,])
        result = np.append(result, self.trimResultFK(res_) , axis=0)
        i=i+1
    loss__ = K.mean(K.square(targetPosition - result), axis=1)
    return loss__.astype(tf.float32)

损耗计算部分可以正常工作。但是,当我要使用自定义损失函数时,出现错误:

  

变量xxxxxx具有None用于渐变。请确保您所有的操作都定义了渐变(即可区分)。没有渐变的常见操作:K.argmax,K.round,K.eval。

由于使用了非Tensorflow函数来计算损失值,因此优化器不知道梯度,因此无法使用Automatic differentiation and gradient自动得出梯度。 为了解决此问题,我尝试实现自定义渐变并将其附加到基于this nice answer的自定义损失函数中。 这是使用我的self.numpy_function方法版本附加渐变的相应部分:

def numpy_function(self, func, inp, dtype=tf.float32, grad=None):
    # Need to generate a unique name to avoid duplicates:
    rnd_name = 'PyFuncGrad' + str(np.random.randint(0, 1E+8))
    tf.RegisterGradient(rnd_name)(grad)
    g = tf.get_default_graph()
    with g.gradient_override_map({"PyFunc": rnd_name}):
        return tf.numpy_function(func, inp, dtype)

我现在有3种方法来覆盖渐变。在numpy域中计算第一个梯度(y_pred的虚拟输出1和0,targetPosition的形状与其numpy数组形状相同):

def np_d_customGrad(self, y_pred, targetPosition):
    return np.ones((self.batch_size,2)).astype(np.float32),np.zeros((self.batch_size ,3 )).astype(np.float32)

然后将其包装为Tensorflow:

def tf_customGrad(self, y_pred, targetPosition):
    d_y_pred_, d_targetPosition_ = tf.numpy_function(self.np_d_customGrad,[y_pred, targetPosition],[tf.float32,tf.float32])
    return d_y_pred_, d_targetPosition_

并最终用于计算自定义损失函数的两个输入(y_pred和targetPosition)的梯度:

def customGrad(self, op, grad):
    y_pred = op.inputs[0]
    targetPosition = op.inputs[1]
    d_y_pred, d_targetPosition  = self.tf_customGrad(y_pred,targetPosition)
    return grad * d_y_pred , grad * d_targetPosition

这会导致尺寸错误:

  

tensorflow.python.framework.errors_impl.InvalidArgumentError:不兼容的形状:[1000,2]与[1000]

我试图在 np_d_customGrad 函数中返回不同形状的零和一。但它不起作用。我假设我的函数必须为自定义损失函数的每个输入参数返回两个梯度之一。 (如果我错了,请纠正我)

我还尝试返回numpy数组结果而不是 loss __ 值,并使用

return K.mean(K.square(targetPosition - actualPosition__), axis=1)
custom_loss 中的

希望Tensorflow本身可以导出梯度,但是不能。

请注意,由于复杂性,我需要花费数月的时间,因此无法在使用TF的python中实现 GET-INDIVIDUAL-LOSS-FROM-GRPC-METHOD 方法。

0 个答案:

没有答案