我正在尝试在Keras中实现对称填充层,就像Caffe实现它一样,我遇到了一个奇怪的问题。
假设我们有一个1x1280x1280x3
图像和3
通道,我们想对它进行卷积,以便它返回一个形状为1x320x320x96
的对象与96
通道。在Caffe中,我们可以在卷积层中设置pad
参数:
input: "image"
input_shape {
dim: 1
dim: 3
dim: 1280
dim: 1280
}
layer {
name: "conv1"
type: "Convolution"
bottom: "image"
top: "conv1"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 96
kernel_size: 11
pad: 5 # Padding parameter
stride: 4
}
}
layer {
name: "relu1"
type: "ReLU"
bottom: "conv1"
top: "conv1"
}
如果你试图用Caffe编译它,conv1
的输出形状确实是1x320x320x96
。
现在让我们使用tf.pad
和Lambda
层与Keras尝试相同的事情:
from keras.layers import Input, Lambda
import tensorflow as tf
image = Input(shape=(1280, 1280, 3),
dtype='float32',
name='image')
sym_pad = Lambda(lamda x: tf.pad(x, [[0, 0], [0, 5], [0, 5], [0, 0]])) # padding = 5
conv1 = Conv2D(filters=96,
kernel_size=11,
strides=(4, 4),
activation=relu,
padding='valid', # valid instead of 'same'
name='conv1')(image)
问题:
如果我们测量从上面的代码定义的conv1
的形状,它将是1x319x319x96
而不是1x320x320x96
。
但是如果我们用2
增加填充,那么使用7x7
pad而不是5x5
,如下所示:
sym_pad = Lambda(lamda x: tf.pad(x, [[0, 0], [0, 5+2], [0, 5+2], [0, 0]])) # padding = 7
当我们通过带有conv1
而不是1x320x320x96
的image
的填充输入时,1x1287x1287x3
将具有所需的1x1285x1285x3
形状(注意,偶数形状图像上的奇数填充改变了卷积的形状,这可能与步幅有关)。
为什么会这样? Caffe会自动通过2
递增每个填充参数吗?或者我做错了什么?
谢谢!
P.S我知道Keras层中的padding=same
参数,但我正在寻找对称填充而不是非对称填充。
如果您正在谈论对称填充,我假设您想要将相同数量的像素填充到图像的左侧以及右侧(顶部和底部相同)。你目前使用tf.pad
做的是向右填充5个像素,向底部填充5个像素。因此,您在两侧填充2.5像素(理论上)。
输出形状由下式给出:
floor((input_size-kernel_size+2*padding_size)/stride_size) + 1
所以在你的情况下,当填充2.5像素时,这会产生319的输出形状。如果你将两侧填充5个像素,你会得到,即320。
在您的示例中,您只将输入填充到底部和右侧。采用:
sym_pad = Lambda(lamda x: tf.pad(x, [[0, 0], [5, 5], [5, 5], [0, 0]]))
得到像Caffe一样的填充物。