如何在keras自定义层中遍历batch_size

时间:2019-12-02 18:44:04

标签: tensorflow keras keras-layer

我想创建一个包含__init__内部张量和自定义点函数的自定义层,以便它为给定批次计算由该批次和内部张量构成的所有可能对上的点函数。

如果我要使用自然的内积,我可以直接写tf.matmul(inputs, self.internal_tensor, transpose_b=True),但我希望能够提供其他 kernel 方法。

MWE:

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Layer


class CustomLayer(Layer):

    def __init__(self, internal_tensor, kernel, **kwargs):
        super().__init__(**kwargs)
        self.internal_tensor = tf.Variable(0., shape=tf.TensorShape((None, 10)), validate_shape=False, name='internal_tensor')
        self.internal_tensor.assign(internal_tensor)
        self.kernel = kernel

    @tf.function
    def call(self, inputs, **kwargs):
        return self.kernel([
            tf.reshape(tf.tile(inputs, [1, self.internal_tensor.shape[0]]), [-1, inputs.shape[1]]),  # because no tf.repeat
            tf.tile(self.support_tensors, [inputs.shape[0], 1]),
        ])


custom_layer = CustomLayer(
    internal_tensor=tf.convert_to_tensor(np.random.rand(30, 10), tf.float32),
    kernel=lambda inputs: inputs[0] + inputs[1],
)
x = np.random.rand(15, 10).astype(np.float32)
custom_layer(x)

# TypeError: Failed to convert object of type <class 'list'> to Tensor. Contents: [1, None]. Consider casting elements to a supported type.

为清楚起见,这是Numpy中的目标工作层:

class NumpyLayer:

    def __init__(self, internal_tensor, kernel):
        self.internal_tensor = internal_tensor
        self.kernel = kernel

    def __call__(self, inputs):
        return self.kernel([
            np.repeat(inputs, len(self.internal_tensor), axis=0),
            np.tile(self.internal_tensor, (len(inputs), 1)),
        ])

numpy_layer = NumpyLayer(
    internal_tensor=internal_tensor,
    kernel=lambda inputs: inputs[0] + inputs[1],
)
numpy_layer(x)

1 个答案:

答案 0 :(得分:0)

因此,所有麻烦都来自使用tf.Tensor.shape而不是tf.shape(tf.Tensor)

这是一个可行的解决方案:

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Layer


class CustomLayer(Layer):

    def __init__(self, internal_tensor, kernel, **kwargs):
        super().__init__(**kwargs)
        self.internal_tensor = tf.Variable(0., shape=tf.TensorShape((None, None)), validate_shape=False, name='internal_tensor')
        self.internal_tensor.assign(internal_tensor)
        self.kernel = kernel

    @tf.function
    def call(self, inputs, **kwargs):
        batch_size = tf.shape(inputs)[0]
        return self.kernel([
            tf.reshape(tf.tile(inputs, [1, tf.shape(self.internal_tensor)[0]]), [-1, inputs.shape[1]]),  # because no tf.repeat
            tf.tile(self.internal_tensor, [batch_size, 1]),
        ])


internal_tensor = np.random.rand(30, 10)
custom_layer = CustomLayer(
    internal_tensor=tf.convert_to_tensor(internal_tensor, tf.float32),
    kernel=lambda inputs: inputs[0] + inputs[1],
)
x = np.random.rand(10, 10).astype(np.float32)
custom_layer(x)

尽管仍然有警告:

WARNING:tensorflow:Entity <bound method CustomLayer.call of <tensorflow.python.eager.function.TfMethodTarget object at 0x7f8e7e2d8400>> could not be transformed and will be executed as-is. Please report this to the AutoGraph team. When filing the bug, set the verbosity to 10 (on Linux, `export AUTOGRAPH_VERBOSITY=10`) and attach the full output. Cause: converting <bound method CustomLayer.call of <tensorflow.python.eager.function.TfMethodTarget object at 0x7f8e7e2d8400>>: ValueError: Unable to locate the source code of <bound method CustomLayer.call of <tensorflow.python.eager.function.TfMethodTarget object at 0x7f8e7e2d8400>>. Note that functions defined in certain environments, like the interactive Python shell do not expose their source code. If that is the case, you should to define them in a .py source file. If you are certain the code is graph-compatible, wrap the call using @tf.autograph.do_not_convert. Original error: could not get source code