由于项目需要需要自己实现卷积算法的逻辑,下面介绍padding填充规则,并且可以用最后面的数据进行简单的验证。
padding属性的意义是定义元素边框和元素内容之间的空间。
在tf.nn.conv2d函数中,当变量padding为VALID和SAME,函数具体是怎么计算的呢?其实是有公式的。为了方便演示,先定义几个变量:
- 输入的尺寸高和宽定义成:in_height,in_width
- 卷积核的高和宽定义成filter_height、filter_width
- 输入的尺寸中高和宽定义成output_height、out_width
- 步长的高宽方向定义成strides_height、strides_width.
一 VALID情况:边缘不填充
输入宽和高的公式分别为:
output_width=(in_width-filter_width+1)/strides_width #(结果向上取整)
output_height=(in_height-filter_height+1)/strides_height #(结果向上取整)
二 SAME情况:边缘填充
# 输出的宽和高将与卷积核没关系,具体公式如下:
output_width=in_width/strides_width #(结果向上取整)
output_height=in_height/strides_height #(结果向上取整)
# 这里有一个很重要的知识点——补零的规则,见如下公式:
pad_height=max((out_height-1)*strides_height+filter_height-in_height,0)
pad_width=max((out_width-1)*strides_width+filter_width-in_width,0)
pad_top=pad_height/2
pad_bottom=pad_height-pad_top
pad_left=pad_width/2
pad_right=pad_width-pad_left
上面公式中
- pad_height:代表高度方向上要填充0的行数。
- pad_width:代表宽度方向要填充0的列数。
- pad_top、pad_bottom、pad_left、pad_right分别代表上、下、左、右这4个方向填充0的行、列数。
- *填充为偶数时,左右和上下对称填充,奇数时优先填充右侧和下侧。
三 规则举例
下面通过一个例子来理解一下padding规则。
假设用一个一维数据来举例,输入是13,filter是6,步长是5,对于padding的取值有如下表示:
3.1 当padding='VALID’
生成宽度为(13-6+1)/5=2(向上取整)个数字。
inputs:
(1 2 3 4 5 6) 7 8 9 10 11 12 13
1 2 3 4 5 (6 7 8 9 10 11) 12 13
12和13丢弃
3.2 当padding=‘SAME’,
生成的宽度为13/5=3(向上取整)
Padding的方式可以如下计算:
Pad_width=(3-1)*5+6-13=3
Pad_left=pad_width/2=3/2=1
Pad_rigth=Pad_width-pad_left=2
在左边补一个0,右边补2个0
input:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 0 0
(0 1 2 3 4 5) 6 7 8 9 10 11 12 13 0 0
0 1 2 3 4 (5 6 7 8 9 10) 11 12 13 0 0
0 1 2 3 4 5 6 7 8 9 (10 11 12 13 0 0)
四 验证
首先,使用这样的输入:
输入的图片是 20*20*1 的,filter的尺寸是 5*5*1, stride是5,这时候是可以直接进行处理的,不需要进行填充:
import tensorflow as tf
b = tf.Variable(tf.ones([1,20,20,1]))
wc1 = tf.Variable(tf.ones([5,5,1,1]))
op1 = tf.nn.conv2d(b, wc1, strides=[1,5,5,1], padding='SAME')
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
res = sess.run(op1)
h = res.shape[1]
w = res.shape[2]
print(res.shape)
print(sess.run(tf.reshape(res, [h, w])))
输出如下:
(1, 4, 4, 1)
[[25. 25. 25. 25.]
[25. 25. 25. 25.]
[25. 25. 25. 25.]
[25. 25. 25. 25.]]
接下来,试验一下最后少了一个元素:
将输入图像的的shape改成 24*24*1 ,这样的话移动完第4次之后,会剩下4个元素,这样就会缺少一个元素,filter和stride不变(接下来这两个都不变),也就是:
b = tf.Variable(tf.ones([1,24,24,1]))
这时候的输出是:
(1, 5, 5, 1)
[[25. 25. 25. 25. 20.]
[25. 25. 25. 25. 20.]
[25. 25. 25. 25. 20.]
[25. 25. 25. 25. 20.]
[20. 20. 20. 20. 16.]]
在右侧和下面分别填充了一列(行)0,也就是:
1 1 1 ...1 1 0
1 1 1 ...1 1 0
1 1 1 ...1 1 0
1 1 1 ...1 1 0
0 0 0 ...0 0 0
所以这样才会出现 20 跟 16 这两种值。
接着调整输入,这次来看如果 最后差两个元素:
b = tf.Variable(tf.ones([1,23,23,1]))
输出:
(1, 5, 5, 1)
[[16. 20. 20. 20. 16.]
[20. 25. 25. 25. 20.]
[20. 25. 25. 25. 20.]
[20. 25. 25. 25. 20.]
[16. 20. 20. 20. 16.]]
这次的输出结果像是有些对称,上下左右各增加了一行(列)0:
0 0 0 ...0 0 0
0 1 1 ...1 1 0
0 1 1 ...1 1 0
0 1 1 ...1 1 0
0 0 0 ...0 0 0
接下来看如果最后少3个元素:
b = tf.Variable(tf.ones([1,22,22,1]))
输出:
(1, 5, 5, 1)
[[16. 20. 20. 20. 12.]
[20. 25. 25. 25. 15.]
[20. 25. 25. 25. 15.]
[20. 25. 25. 25. 15.]
[12. 15. 15. 15. 9.]]
最后缺少3个元素的时候,在前面(左边和上边)会添加一行(列)0, 在后边(下边和右边)会增加两行(列)0:
0 0 0 ...0 0 0
0 1 1 ...1 0 0
0 1 1 ...1 0 0
0 1 1 ...1 0 0
0 0 0 ...0 0 0
最后缺少4个元素,按照上面的规律会在前后都增加两行(列):
b = tf.Variable(tf.ones([1,21,21,1]))
输出:
(1, 5, 5, 1)
[[ 9. 15. 15. 15. 9.]
[15. 25. 25. 25. 15.]
[15. 25. 25. 25. 15.]
[15. 25. 25. 25. 15.]
[ 9. 15. 15. 15. 9.]]
注:如果最后需要补全的数量是n:
n 如果是奇数,那么前面增加 (n-1)/2,后面增加(n+1)/2
n 如果是偶数,那么前后都增加 n/2
本文介绍了在TensorFlow的卷积操作tf.nn.conv2d中,如何使用padding='SAME'进行边缘填充,详细解析了填充规则,并通过实例验证了计算方法。内容包括VALID和SAME两种情况的计算,以及不同填充数量对输出的影响。
4561

被折叠的 条评论
为什么被折叠?



