今天用Keras编程的时候发现一个问题,

···
input_layer = K.layers.Input(shape=(10,))

x = K.layers.Dense(20)(input_layer)
x = K.layers.Dense(20)(x)
···
以上写法是可行的,但是以下写法却不行

L = K.layers.Dense(20)
y = L(input_layer)
y = L(y)

前两个表达式正常,到了第3个表达式y=L(y)的时候就报input_shape错误。百思不得其解,按照Python编程的原则,一切皆对象

L = K.layers.Dense(20)
L(x)

K.layers.Dense(20)(x)

有何不同?

一番尝试,发现奥妙在于Keras Layers的设计。看一下官方的对于自定义Layer的说明,

call(x): this is where the layer's logic lives. Unless you want your layer to support masking, you only have to care about the first argument passed to call: the input tensor.

也就是说,当layer的callmethod被调用时,layer才实际存在,此时将传入input_shape。如果call没有被调用,此时layer中并没有input_shape的信息。

举例说明,

L = K.layers.Dense(20)
L.input_shape

此时编译器报错`AttributeError: The layer has never been called and thus has no defined input shape. 再看以下代码,

L = K.layers.Dense(20)
y = L(input_layer)
L.input_shape

此时编译器不报错,输出(None, 10)。照理说第二段代码并没有对L做任何操作,只是将L(input_layer)赋给了y,但是此时L确获得了input_shape这个参数。

结合call(x)的定义,一开始遇到的问题也就明白了。表达式y = L(input_layer)调用了Lcallmethod,此时L这个layer才正式被初始化,其input_shape也根据传入的input_layer被赋值 。因此,此时的L其实已经跟表达式K.layers.Dense(20)不一样了,后者未被调用,input_shape不存在。

以下这段代码之所以报input_shape错误,就是因为y = L(input_layer)使得L的input_shape被初始化为(10,)。因次当第三个表达式y=L(y)y被传入L时,由于y的shape并不是(10,),而是(20,),与L中input_shape的值不一致,编译器报错。

L = K.layers.Dense(20)
y = L(input_layer)
y = L(y)