1:卷积运算原理(直接看图)
①由图可知,output[0][0] = 视野域 * 卷积核(矩阵点击运算,对应位相乘然后求和,视野域形状与卷积核一致),而output[0][1] = 下一视野域 * 卷积核,如下图:
下一视野域的挪动位置与超参数strides = s(这里为1)有关,s为多少每次就挪动多少个格子(挪动到尽头时还未到达s个格子则放弃该次卷积运算),到达当前行尽头时,则output第一行的计算就完成了;②这次向下挪动s格,列转到第0列(下标从0开始)然后开始output的第二行计算;③重复上述操作,最后输出output。
output的形状满足公式:1 + (n - k) // s,其中input形状为 nxn(这里5x5),卷积核形状为 kxk(这里3x3),双斜杠为整除。
2:padding的取值(VALID 或 SAME)
①当padding = VALID时,结果为上述案例。
代码演示(tensorflow版):
import tensorflow as tf
import numpy as np
# input.shape: [sample, height, width, in_channel]
# kernel.shape: [k, k, in_channel, out_channel]
input = tf.constant(range(1, 26), dtype=tf.float32)
input = tf.reshape(input, (1, 5, 5, 1))
kernel = tf.ones((3, 3, 1, 1)) # 卷积核
tf.squeeze(input), tf.squeeze(kernel) # tf squeeze去除维度 == 1的轴,便于阅读
output = tf.nn.conv2d(a, kernel, strides=1, padding='VALID') # strides 也可以 = [1, 1] ,分别设置高与宽方向的步幅
# output.shape: [sample, Df, Df, out_channel], Df=1 + (n - k) // s
output.shape
tf.squeeze(output)
结果符合预期!
②padding = SAME
卷积运算如下图
上下左右填充的0行数为 (k - 1) // 2,且k的取指一般为奇数;当 k 取偶数时,右边与下边的0行数就会比左边与上边的0行数多1行。当padding = same时,pytorch中strides 必须等于1
代码演示:
output_same = tf.nn.conv2d(input, kernel, strides=[1, 1, 1, 1], padding='SAME')
tf.squeeze(output_same)
结果符合预期。
欢迎提问!