使用输出一半大小的输入填充 Keras

数据挖掘 Python 神经网络 喀拉斯
2022-02-08 14:44:21

这是我正在研究的 Keras 模型:

model = Sequential()
model.add(Conv2D(64, kernel_size=(7, 7), strides = 2, padding = 3,
                 input_shape=input_shape)) # (224,224,64)

model.add(MaxPooling2D(pool_size=(2, 2), strides = 2)) # (112,112,64)
model.add(Conv2D(192, kernel_size = (3,3), padding = 1)) #(112,112,192)
model.add(MaxPooling2D(pool_size = (2,2),strides = 2)) #(56,56,192)
model.add(Conv2D(128, kernel_size = (1,1))) #(56,56,128)
model.add(Conv2D(256, kernel_size = (3,3), padding = 1)) #(56,56,256)
model.add(Conv2D(256, kernel_size = (1,1))) #(56,56,256)
model.add(Conv2D(512, kernel_size = (3,3),padding = 1)) #(56,56,512)
model.add(MaxPooling2D(pool_size = (2,2), strides = 2)) #(28,28,512)
model.add(Conv2D(256, kernel_size = (1,1))) #(28,28,128)
model.add(Conv2D(512, kernel_size = (3,3), padding = 1)) #(28,28,512)
model.add(Conv2D(256, kernel_size = (1,1))) #(28,28,128)
model.add(Conv2D(512, kernel_size = (3,3), padding = 1)) #(28,28,512)
model.add(Conv2D(256, kernel_size = (1,1))) #(28,28,128)
model.add(Conv2D(512, kernel_size = (3,3), padding = 1)) #(28,28,512)
model.add(Conv2D(256, kernel_size = (1,1))) #(28,28,128)
model.add(Conv2D(512, kernel_size = (3,3), padding = 1)) #(28,28,512)
model.add(Conv2D(512, kernel_size = (1,1))) #(28,28,512)
model.add(Conv2D(1024,kernel_size = (3,3), padding = 1)) #(28,28,1024)
model.add(MaxPooling2D(pool_size = (2,2), strides = 2)) #(14,14,1024)
model.add(Conv2D(512, kernel_size = (1,1))) #(14,14,512)
model.add(Conv2D(1024,kernel_size = (3,3), padding = 1)) #(14,14,1024)
model.add(Conv2D(512, kernel_size = (1,1))) #(14,14,512)
model.add(Conv2D(1024,kernel_size = (3,3), padding = 1)) #(14,14,1024)
model.add(Conv2D(1024, kernel_size = (3,3), padding = 1)) #(14,14,1024)
model.add(Conv2D(1024, kernel_size = (3,3), strides = 2, padding = 3)) #(7,7,1024)
model.add(Conv2D(1024,kernel_size = (3,3), padding = 1)) #(7,7,1024)
model.add(Conv2D(1024, kernel_size = (3,3), padding = 1)) #(7,7,1024)

model.add(Flatten())
model.add(Dense(4096))
model.add(Dense(7*7*30))
model.add(Reshape(7,7,30))

当我编译它时,我得到一个填充错误,因为 Keras 只知道“相同”、“有效”和“随意”。我理解这些,但我真的需要在某处填充等于 3,因为我的输出应该是输入的一半(我们的步幅等于 2)。我真的不知道如何解决它。如果我们想以步长 2 将输入缩小一半,如何进行填充?

1个回答

如果您的目标只是将过滤器的大小减半,则可以考虑使用填充以外的其他方法,例如扩张卷积。看看这篇论文,了解一些想法和带有图片的很好的解释。只是快速考虑一下您的尺寸,我不确定您是否可以很容易地从 14 变为 7。不过,达到 8 或 5 很简单。


如果您刚开始学习 KEras,那么一件事并不总是显而易见的,那就是您可以直接从 Tensorflow 库中将 Tensorflow 操作与您的 Keras 代码混合使用。

在 TF 中有一个名为 的函数pad,它允许您在张量的每一侧手动指定填充。还有一些选项可以说明填充是否用零完成,或者原始张量中的值是否重复/镜像(使用mode参数)。

您可以尝试使用它来填充图层。我可以向您展示如何填充张量以获得您想要的效果:

from keras.models import Sequential, Model
from keras.layers import (Input, Conv2D, MaxPooling2D, 
                          Flatten, Dense, Reshape, Lambda)
import tensorflow as tf

input_shape = (448, 448, 3)
batch_shape = (None,) + input_shape
raw_input = tf.placeholder(dtype='float16', shape=batch_shape)
paddings = tf.constant([[0, 0],   # the batch size dimension
                        [3, 3],   # top and bottom of image
                        [3, 3],   # left and right
                        [0, 0]])  # the channels dimension

padded_input = tf.pad(raw_input, paddings, mode='CONSTANT',
                      constant_values=0.0)  # pads with 0 by default

padded_shape = padded_input.shape     # (454, 454, 3) because we add 2*3 padding

input_layer = Input(padded_shape, batch_shape, tensor=padded_input)
layer0 = Conv2D(192, kernel_size = (3,3), padding='valid')(input_layer)
layer1 = MaxPooling2D(pool_size=(2, 2), strides = 2)(layer0) 
layer2 = Conv2D(192, kernel_size = (3,3), padding='valid')(layer1)
layer3 = MaxPooling2D(pool_size = (2,2),strides = 2)(layer2)
layer4 = Conv2D(512, kernel_size = (3,3), padding='valid')(layer3)
layer5 = MaxPooling2D(pool_size = (2,2), strides = 2)(layer4)
layer6 = Conv2D(256, kernel_size = (1,1), padding='valid')(layer5)
# layer6.shape --> [Dimension(None), Dimension(55), Dimension(55), Dimension(256)]

layer6_padded = tf.pad(layer6, paddings, mode='CONSTANT')
layer6_output = Input(input_shape=layer6_padded.shape)(layer6_padded)

# This will end up giving this error at compilation:
# RuntimeError: Graph disconnected: ...,

layer7 = Conv2D(1024, kernel_size=(3, 3), strides=2)(layer6_output)
layer8 = Flatten()(layer7)
layer9 = Dense(4096)(layer7)
layer10 = Dense(7*7*30)(layer8)
output_layer = Reshape((7, 7, 30))(layer10)

# The following both fail to get the graph as we would like it
model = Model(inputs=[input_layer], outputs=[output_layer])
#model = Model(inputs=[input_layer, layer6_output], outputs=[output_layer])

model.compile('adam', 'mse')
model.summary()

然后我无法将此张量带回 Keras 模型(作为一个层,这是必需的),因为使用Input对象的标准方式强制它成为计算图的入口点,但我们希望填充张量形成中间层。

如果您不强制填充张量进入 Keras 层,则属性将丢失:

# AttributeError: 'Tensor' object has no attribute '_keras_history'

您可以通过在我们填充之前添加​​层中的属性来破解:

#layer6_output._keras_history = layer6._keras_history

不幸的是,我仍然遇到了其他错误。

如果你能找到任何东西,也许你可以在 StackOverflow 上发布一个新问题,询问如何做到这一点我确实快速尝试了使用创建两个图表然后加入它们的想法,但没有成功。