Deep learning 如何在Tensorflow 2/keras自定义层中使用基于numpy的外部库函数?

Deep learning 如何在Tensorflow 2/keras自定义层中使用基于numpy的外部库函数?,deep-learning,neural-network,pytorch,tensorflow2.0,keras-layer,Deep Learning,Neural Network,Pytorch,Tensorflow2.0,Keras Layer,如果有人能帮助我理解以下问题,我将不胜感激 我试图通过使用keras在tensorflow 2中实现一个自定义层(它是从类层派生的层) 我已经重写了构建和调用函数 当我编写调用函数时,我需要从只接受numpy数组的外部库调用一个方法。这是一个非常复杂的函数,当然它不使用张量流函数。 我的调用函数接收一个张量输入,将其转换为numpy(by.numpy()函数),从另一个库调用外部方法,然后将numpy数组转换回张量 在这里,我遇到了一些问题,并尝试了不同的解决方案 如果我运行代码,它会告诉我…o

如果有人能帮助我理解以下问题,我将不胜感激

我试图通过使用keras在tensorflow 2中实现一个自定义层(它是从类层派生的层)

我已经重写了构建和调用函数

当我编写调用函数时,我需要从只接受numpy数组的外部库调用一个方法。这是一个非常复杂的函数,当然它不使用张量流函数。 我的调用函数接收一个张量输入,将其转换为numpy(by.numpy()函数),从另一个库调用外部方法,然后将numpy数组转换回张量

在这里,我遇到了一些问题,并尝试了不同的解决方案

  • 如果我运行代码,它会告诉我…ops.Tensor没有方法.numpy()。如果我理解正确,这是因为我在调用函数的输入中接收到张量的类型,我需要使用渴望模式
  • 如果我在拟合期间通过将run_急切地标记设置为true进行编译,它会告诉我缺少渐变。我希望实现某种形式的自动梯度计算,但也许这不是目前正在发生的事情
  • 源代码:

    class SimpleLayer(tf.keras.layers.Layer):
        def __init__(self):
            super(SimpleLayer, self).__init__()
    
        def build(self, input_shape):
            shape_a = input_shape[0]                #batch_size
            shape_b = int(input_shape[1])           #height
            shape_c = int(input_shape[2])           #width
            shape_d = input_shape[3]                #channel_number
            self.w = self.add_weight(shape=(shape_d*shape_a, 2, shape_b, shape_c),
                                     initializer='random_uniform', dtype='float64',
                                     trainable=True)
    
    
        def call(self, inputs):
            tf_inputs = inputs.numpy()
            sft = tr.transform(tf_inputs) # call to the external library
            transformed = tf.math.multiply(sft, self.w)
            conv = tf.zeros(np.shape(inputs))
            conv = tr.inv_transform(inputs, transformed) # another call to a function that also converts to tensor
            return conv. # this is a tensor!
    
    
    .....
    
    model = tf.keras.Sequential([
        layers.experimental.preprocessing.Rescaling(1./255),
        pl.SimpleLayer(),
        layers.Activation('relu'),
        layers.MaxPooling2D(),
        pl.SimpleLayer(),
        layers.Activation('relu'),
        layers.Flatten(),
        layers.Dense(128, activation='relu'),
        layers.Dense(num_classes)
    ])
    
    model.compile(
        optimizer='adam',
        loss=tf.losses.SparseCategoricalCrossentropy(from_logits=True),
        run_eagerly=True,  # adding this to avoid graph building
        metrics=['accuracy'])
    
    history = model.fit(train_images, train_labels, epochs=3, batch_size=20,
                        validation_data=(test_images, test_labels))
    
    有什么解决办法吗?我可以只使用tensorflow 2函数来处理张量吗?或者我遗漏了什么


    我也在考虑改用Pytork(我还不知道),但我担心会有同样的问题。您有什么建议吗?

    梯度不能通过
    numpy
    函数作为
    numpy
    没有任何自动加载功能

    您的自定义函数在
    tensorflow2.x
    pytorch
    中都不起作用,因为未记录对
    numpy
    数组的操作

    对于您的
    调用
    代码(在PyTorch中,它将是
    转发
    ,否则非常类似),请参阅注释:

    def call(self, inputs):
        tf_inputs = inputs.numpy() # gradient breaks
        sft = tr.transform(tf_inputs) # still numpy
        transformed = tf.math.multiply(sft, self.w)
        conv = tf.zeros(np.shape(inputs))
        conv = tr.inv_transform(inputs, transformed)
        return conv # Tensor with no gradient history
    
    这会发生在所有的
    SimpleLayer
    层上

    可能的解决方案
    • tensorflowpytorch中以可微的方式对这些操作进行编码(假设它们是可微的,并且不使用像argmax这样的操作)(后者更简单、更直观,您可以更轻松地使用它)
    • 如果您的复杂函数使用
      numpy
      并且是可微的,那么您可以通过将
      np.op
      重写为
      torch.op
      来使用PyTorch对其进行编码,因为它们的API非常相似,并且几乎无缝地互操作
    • 您可以使用而不是
      tf
      pytorch
      作为“JAX可以自动区分本地Python和NumPy函数”。根据您的应用程序,可能值得一试