如何在 keras/tensorflow 中定义秩大于 4 的张量上的二维卷积



我正在尝试找到一种方法来对维数高于 4 的张量执行 2D 卷积,这是 keras.layers.Conv2D 和keras.backend.conv2d所需的输入秩。我的意思是,我希望能够使用[batch,<some_other_dimensions>, W, H, C],而不是大小[batch, W, H, C]输入,并且其他维度基本上以与"批处理"相同的方式处理(例如不受卷积的影响)。不出所料,这会引发错误,因此重塑数组似乎是最直接的解决方案,但是,这存在问题(如下所述)。

在重塑时,我弄乱了 Keras 看到的批处理维度,所以我需要使用keras.backend.reshape,而不是 keras.layers.Reshape,它似乎无法访问数据的批处理维度。通过使用lambda层和keras.backend.reshape,我们可以制作大小为[batch*<some_other_dimensions>,W,H,C]的输入数组,然后在执行卷积后再次重塑它们。但是,该层必须能够构成完全卷积网络的一部分,该网络可以处理任意图像大小,这些图像大小具有未定义的 W 和 H(在实例化输入层的形状时设置为 None)。因此,我们最终将一个具有两个未定义空间维度的形状传递给keras.backend.reshape,它显然不能使用:[batch*<some_other_dimensions>,None,None,C].

当显式声明宽度和高度时,我可以让它工作(正如您在我的代码中看到的那样)。但是,我真的不想牺牲摄取任意大小的空间维度的能力,因为能够这样做对我的项目来说很重要。

我能想到的唯一其他选择实际上是定义我自己的自定义层,该层可以处理 2D 卷积的> 个 4 维输入。我真的不知道从哪里开始,但如果人们认为这是最可行的路线,那么建议将非常受欢迎。或者也许有一个漂亮的 lambda 层可以解决我的问题?

from keras.layers import Input, Conv2D, Lambda
import keras.backend as K
from keras.models import Model

def reshape_then_conv(data_shape):
input = Input(shape=data_shape)
#should equal (None, *data_shape) because batch is prepended as None
print('      INPUT SHAPE: ', input.shape)
#reshaping input into 4D
reshaped = Lambda(lambda x: K.reshape(x,(-1, *input.shape[3:])))(input)
print('    AFTER RESHAPE: ', reshaped.shape)
#convolve new 4D tensor
convolved = Conv2D(10,(3,3),strides=2)(reshaped)
print('AFTER CONVOLUTION: ', convolved.shape)
#reshaping back but keeping new spatial and channel dimensions from convolution
reshaped_back = Lambda(lambda x: K.reshape(x,(-1,*input.shape[1:3],*convolved.shape[-3:])))(convolved)
return Model(inputs=input,outputs=reshaped_back)

#images of size 100,100,3 in 4-by-4 set
layer = reshape_then_conv([4,4,100,100,3])
print('     OUTPUT SHAPE: ', layer.output_shape,'n')
#images of undefined size in 4-by-4 set
layer = reshape_then_conv([4,4,None,None,3])
print('     OUTPUT SHAPE: ', layer.output_shape)

正如预期的那样,对"reshape_then_conv"的第一次调用有效,因为我们显式设置了宽度和高度。但是,第二个示例给出了:

类型错误:无法将类型的对象转换为张量。>内容: (-1, 维度(无), 维度(无), 维度 (3)).请考虑将元素>转换为受支持的类型。

提前感谢您的任何见解!

更新

感谢@DMolony的回答,我重新排列了代码如下......

from keras.layers import Input, Conv2D, Lambda
import keras.backend as K
from keras.models import Model
def reshape_then_conv(data_shape):
input = Input(shape=data_shape)
print('      INPUT SHAPE: ', input.shape)
new_shape = K.concatenate((K.variable([-1],dtype='int32'),K.shape(input)[3:]))
#reshaping input into 4D
reshaped = Lambda(lambda x: K.reshape(x,new_shape))(input)
print('    AFTER RESHAPE: ', reshaped.shape)
#convolve new 4D tensor
convolved = Conv2D(10,(3,3),strides=2)(reshaped)
print('AFTER CONVOLUTION: ', convolved.shape)
returning_shape = K.concatenate((K.variable([-1],dtype='int32'),K.shape(input)[1:3],K.shape(convolved)[-3:]))
#reshaping back but keeping new spatial and channel dimensions from convolution
reshaped_back = Lambda(lambda x: K.reshape(x,returning_shape))(convolved)
return Model(inputs=input,outputs=reshaped_back)
#images of size 100,100,3 in 4-by-4 set
layer = reshape_then_conv([4,4,100,100,3])
print('     OUTPUT SHAPE: ', layer.output_shape,'n')
#images of undefined size in 4-by-4 set
layer = reshape_then_conv([4,4,None,None,3])
print('     OUTPUT SHAPE: ', layer.output_shape)

当重塑而不是使用静态形状时,例如

input.shape[1:3]  

尝试提供动态形状,例如

K.shape(input)[1:3]

最新更新