以功能样式链接自定义Keras图层

时间:2020-03-19 17:06:25

标签: python keras tensorflow2.0 tf.keras

我想使用tf.keras'功能性API构建模型。我的模型很大,因此我想通过继承tf.keras.layers.Layer来创建自定义图层。以下是我受TensorFlow's documentation启发的尝试。

import tensorflow as tf

class Conv2D(tf.keras.layers.Layer):
    def __init__(self):
        super().__init__()

        input_layer = tf.keras.layers.Input(
            shape=(256, 256, 3)
        )
        self.conv = tf.keras.layers.Conv2D(
            filters=16,
            kernel_size=3,
            strides=(1, 1),
            padding="same"
        )(input_layer)

    def call(self, inputs):
        return self.conv(inputs)

outer_input_layer = tf.keras.layers.Input(
    shape=(256, 256, 3)
)
x = Conv2D()(outer_input_layer)

此代码因以下错误而崩溃。

Traceback (most recent call last):
  File "c:\Users\user\.vscode\extensions\ms-python.python-2020.2.64397\pythonFiles\ptvsd_launcher.py", line 48, in <module>
    main(ptvsdArgs)
  File "c:\Users\user\.vscode\extensions\ms-python.python-2020.2.64397\pythonFiles\lib\python\old_ptvsd\ptvsd\__main__.py", line 432, in main
    run()
  File "c:\Users\user\.vscode\extensions\ms-python.python-2020.2.64397\pythonFiles\lib\python\old_ptvsd\ptvsd\__main__.py", line 316, in run_file
    runpy.run_path(target, run_name='__main__')
  File "C:\Users\user\code\.env\lib\runpy.py", line 263, in run_path
    pkg_name=pkg_name, script_name=fname)
  File "C:\Users\user\code\.env\lib\runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "C:\Users\user\code\.env\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "c:\Users\user\code\tests.py", line 23, in <module>
    x = Conv2D()(outer_input_layer)
  File "C:\Users\user\code\.env\lib\site-packages\tensorflow_core\python\keras\engine\base_layer.py", line 773, in __call__        
    outputs = call_fn(cast_inputs, *args, **kwargs)
  File "C:\Users\user\code\.env\lib\site-packages\tensorflow_core\python\autograph\impl\api.py", line 237, in wrapper
    raise e.ag_error_metadata.to_exception(e)
TypeError: in converted code:

    c:\Users\user\code\tests.py:18 call  *
        return self.conv(inputs)
    C:\Users\user\code\.env\lib\site-packages\tensorflow_core\python\autograph\impl\api.py:447 converted_call
        f in m.__dict__.values() for m in (collections, pdb, copy, inspect, re)):
    C:\Users\user\code\.env\lib\site-packages\tensorflow_core\python\autograph\impl\api.py:447 <genexpr>
        f in m.__dict__.values() for m in (collections, pdb, copy, inspect, re)):
    C:\Users\user\code\.env\lib\site-packages\tensorflow_core\python\ops\math_ops.py:1351 tensor_equals
        return gen_math_ops.equal(self, other, incompatible_shape_error=False)
    C:\Users\user\code\.env\lib\site-packages\tensorflow_core\python\ops\gen_math_ops.py:3240 equal
        name=name)
    C:\Users\user\code\.env\lib\site-packages\tensorflow_core\python\framework\op_def_library.py:477 _apply_op_helper
        repr(values), type(values).__name__, err))

    TypeError: Expected float32 passed to parameter 'y' of op 'Equal', got 'collections' of type 'str' instead. Error: Expected float32, got 'collections' 
of type 'str' instead.

我的方法有什么问题?

1 个答案:

答案 0 :(得分:1)

自定义层没有“输入”层。那没有多大意义。输入是调用时传递给图层的内容。

所以:

import tensorflow as tf

class ConvBN(tf.keras.layers.Layer):
    def __init__(self, activation, name):
        super().__init__()

        #here you just "store" the layers, you don't use them
        #you also store any other property you find necessary for the call
        self.conv = tf.keras.layers.Conv2D(
            filters=16,
            kernel_size=3,
            strides=(1, 1),
            padding="same",
            name = name+'_conv'
        )
       self.bn = tf.keras.layers.BatchNormalization(name = name + "_bn")
       self.activation = tf.keras.layers.Activation(activation, name = name + "_act")

    def call(self, inputs):
        #here you "use" the layers with the given input to produce an output
        out = self.conv(inputs)
        out = self.bn(out)
        out = self.activation(out)

        return out

如果您不打算多次使用“同一层”,也可以创建更简单的对象:

def convGroup(input_tensor, activation, name):
    out = tf.keras.layers.Conv2D(
            filters=16,
            kernel_size=3,
            strides=(1, 1),
            padding="same",
            name = name+'_conv'
        )(input_tensor)
    out = tf.keras.layers.BatchNormalization(name = name + "_bn")(out)
    out = tf.keras.layers.Activation(activation, name = name + "_act")(out)

    return out