为什么 `tf.pad` 填充参数需要额外增加以确保准确性?
Why do `tf.pad` padding arguments need additional incrementation for accuracy?
我正在尝试在 Keras 中实现一个对称填充层,这就像 Caffe 实现它的方式一样,但我遇到了一个奇怪的问题。
假设我们有一个具有 3
个通道的 1x1280x1280x3
图像,我们想对其执行卷积,使其 returns 成为一个形状为 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
填充而不是 5x5
,像这样:
sym_pad = Lambda(lamda x: tf.pad(x, [[0, 0], [0, 5+2], [0, 5+2], [0, 0]])) # padding = 7
当我们传递形状为 1x1287x1287x3
而不是 1x1285x1285x3
的填充输入 image
时,conv1
将具有所需的形状 1x320x320x96
( 注意偶数形状图像上只有奇数填充会改变卷积的形状,这可能与步长有关)。
为什么会这样? 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 中相同的填充。
我正在尝试在 Keras 中实现一个对称填充层,这就像 Caffe 实现它的方式一样,但我遇到了一个奇怪的问题。
假设我们有一个具有 3
个通道的 1x1280x1280x3
图像,我们想对其执行卷积,使其 returns 成为一个形状为 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
填充而不是 5x5
,像这样:
sym_pad = Lambda(lamda x: tf.pad(x, [[0, 0], [0, 5+2], [0, 5+2], [0, 0]])) # padding = 7
当我们传递形状为 1x1287x1287x3
而不是 1x1285x1285x3
的填充输入 image
时,conv1
将具有所需的形状 1x320x320x96
( 注意偶数形状图像上只有奇数填充会改变卷积的形状,这可能与步长有关)。
为什么会这样? 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 中相同的填充。