如何在我的层中找到不可微分的操作?

How do I find the non differentiable operation in my layer?

我正在尝试在 keras 中创建一个具有许多操作的相当复杂的 lambda 层。我实现后得到了一个ValueError: No gradients provided for any variable

虽然我只使用 keras 操作来转换数据,(除了我使用 numpy 创建的常量,我后来将其添加到 Tensor 中)我明白必须有一些不可微分的操作。现在我想知道如何找出它是哪一个,以便找到解决方法。

我还不想发布任何代码,因为它是竞赛的一部分,我想自己解决这个问题。如果因此而难以理解我的问题,请告诉我。但是,我可以列出我正在使用的所有功能:

from tensorflow.keras import backend as K
from tensorflow.python.keras.layers import Lambda

...
def my_lambda_function(x):
    # uses:
    K.batch_dot
    K.cast
    K.clip
    K.concatenate
    K.one_hot
    K.reshape
    K.sum
    K.tile  # only applied to a constant created in numpy

...
# using the function in a model like this:
my_lambda_layer = Lambda(my_lambda_function)
result_tensor = my_lambda_layer(some_input)

我认为 K.one_hot 可能有问题,但我想要一种方法来确定这一点,然后再尝试使其可微分

睡了几个小时后,这是我的简单解决方案:创建一个简单的 NN 用于测试并添加一个 lambda 层,我在其中单独尝试所有功能。然而,这只是发现问题的一种间接方式。这是我的代码:

from tensorflow.python.keras.layers import Input, Conv2D, MaxPooling2D, UpSampling2D, Conv2DTranspose, Lambda
from tensorflow.python.keras.models import Sequential
from tensorflow.keras.datasets.mnist import load_data

from tensorflow.keras import backend as K

import tensorflow as tf
import numpy as np

(x_train, y_train), (x_test, y_test) = load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
x_train, x_test = np.reshape(x_train, (-1, 28, 28, 1)), np.reshape(x_test, (-1, 28, 28, 1))


def test_function(x):
    x_int = K.cast(x, tf.int16)  # this was one of the gradient killers in my case
    return K.cast(x_int, tf.float16)


model = Sequential()
model.add(Input(shape=(28, 28, 1)))
model.add(Conv2D(10, (5, 5), padding='same', activation='relu'))
model.add(MaxPooling2D())
model.add(Lambda(test_function))
model.add(UpSampling2D())
model.add(Conv2DTranspose(4, (5, 5), padding='same', activation='relu'))
model.add(Conv2DTranspose(1, (3, 3), padding='same', activation='sigmoid'))

model.compile(optimizer='adam',
              loss='mse',
              metrics=['accuracy'])

model.fit(x_train, x_train, epochs=5)
model.evaluate(x_test, x_test)

这对我有用,但我希望有更好的解决方案。

顺便说一句。我可以使用这些函数来近似地板操作(这也会杀死梯度):

def a(x):
    two_pi = 2 * math.pi
    two_pi_x = x * two_pi
    sine = K.sin(two_pi_x)
    numerator = sine + two_pi_x
    return numerator / two_pi


def approximated_floor(x):
    x2 = a(a(a(x))) - 0.5
    return x2