tf.nn.conv2d与depthwise_conv2d函数
参数
首先需要注意的是, tf.nn.conv2d与tf.nn.depthwise_conv2d两个函数的参数基本相同, 具体如下所示
input
\textbf{input}
input: 指该卷积层的输入, 通常为图像. 输入的维数为由参数
data_format
\textbf{data\_format}
data_format决定, 具体见该参数说明.
filter
\textbf{filter}
filter: 相当于CNN中的卷积核,要求是一个4维Tensor,四个维数大小依次为卷积核高度, 卷积核宽度, 输入通道数量以及输出通道数量(在depthwise_conv2d中为输出通道乘子), 记为
W
∈
R
H
f
×
W
f
×
C
i
×
C
o
(
C
m
)
\mathbf{W} \in \mathbb{R}^{H_f \times W_f \times C_i \times C_o (C_m)}
W∈RHf×Wf×Ci×Co(Cm).
strides
\textbf{strides}
strides: 卷积的滑动步长, 通常为长度为4的向量, 表示卷积核在4个维度上的滑动步长, 记为
s
=
[
s
N
,
s
H
,
s
W
,
s
C
]
T
\boldsymbol{s} = \left[ s_N, s_H, s_W, s_C \right]^T
s=[sN,sH,sW,sC]T.
padding
\textbf{padding}
padding: string类型的量, 只能是”SAME”或”VALID”其中之一, 这个值决定了不同边缘填充方式.
data_format
\textbf{data\_format}
data_format: string类型的变量, 用于指定输入数据的shape, 取值为"NHWC"与"NCHW"中的一个. 其中,
N
N
N表示批大小(batch size),
H
H
H表示高度(height),
W
W
W表示宽度(width),
C
C
C表示输入通道(channel). 默认值通常为"NHWC", 此时记输入数据为
I
∈
R
N
×
H
i
×
W
i
×
C
i
\mathbf{I} \in \mathbb{R}^{N \times H_i \times W_i \times C_i }
I∈RN×Hi×Wi×Ci
计算过程
在计算过程中, 两个函数的计算方式仅在卷积后求和时有所区别. 因此, 这里介绍一下卷积的计算过程.
卷积计算
对于输入
I
∈
R
N
×
H
i
×
W
i
×
C
i
\mathbf{I} \in \mathbb{R}^{N \times H_i \times W_i \times C_i }
I∈RN×Hi×Wi×Ci与卷积核
W
∈
R
H
f
×
W
f
×
C
i
×
C
o
\mathbf{W} \in \mathbb{R}^{H_f \times W_f \times C_i \times C_o}
W∈RHf×Wf×Ci×Co, 卷积操作表示为
O
=
I
∗
W
\mathbf{O} = \mathbf{I} * \mathbf{W}
O=I∗W
根据输入的参数, 卷积操作的具体计算方法可分为"VALID"与"SAME"两种, 我们使用一维卷积来介绍这两种计算过程的区别, 首先定义输入
I
\mathbf{I}
I 的长度(Length)为
L
i
L_i
Li, 即
I
∈
R
L
i
\mathbf{I} \in \mathbb{R}^{L_i}
I∈RLi, 卷积核为
W
∈
R
L
f
\mathbf{W} \in \mathbb{R}^{L_f}
W∈RLf, 滑动步长为
s
L
s_L
sL.
首先需要注意的是, "VALID"与"SAME"本质上的区别在于输出的大小与输入大小是否相同(即SAME表示的是输出大小与输入大小相同), 而控制这一点的方法则是通过在输入两侧(一维情况是两侧, 二维则是上下左右四侧, 亦可扩展至三维输入中)增加0, 具体过程将在padding = "SAME"的章节中进行分析. 接下来首先介绍padding = "VALID"的情况.
padding = “VALID”
VALID情况的下卷积过程如图所示
卷积过程从第一个元素开始, 然后根据滑动步长进行滑动. 需要注意的是, 为了使卷积时卷积核对应位置不会超出输入范围, 有时候需要舍弃最后一些元素, 这是由于在卷积时, 最后一次卷积核对应位置的末位索引不能超过输入长度, 即满足下式
(
n
−
1
)
s
L
+
1
+
(
L
f
−
1
)
≤
L
i
(n-1) s_L + 1 + (L_f -1) \leq L_i
(n−1)sL+1+(Lf−1)≤Li
即可得到卷积操作的次数
n
n
n
n
=
⌊
L
i
−
L
f
s
L
⌋
+
1
n = \lfloor \frac{L_i - L_f}{s_L} \rfloor + 1
n=⌊sLLi−Lf⌋+1
其中,
⌊
⌋
\lfloor \quad \rfloor
⌊⌋表示下取整. 而舍弃(Drop)的长度则为
L
d
=
L
i
−
[
(
n
−
1
)
s
L
+
L
f
]
L_d = L_i - \left[ (n-1)s_L + L_f \right]
Ld=Li−[(n−1)sL+Lf]
padding = “SAME”
SAME情况的卷积过程如图所示
可以看到, 在输入的前后分别添加了一些元素使得卷积过程满足一些条件, 称为padding(通常添加的为0元素, 称为zero-padding). 接下来将详细讨论添加元素的规则.
在前面提到过, SAME的意义是使得输出与输入的长度相等. 然而, 这只是当滑动步长为1时的情况. 不过这也为卷积的滑动步长大于1时的操作提供了一个基准原则. 事实上, 在任意滑动长度
s
L
s_L
sL下, 输出长度
L
o
L_o
Lo满足下式
L
o
=
⌈
L
i
s
L
⌉
L_o = \lceil \frac{L_i}{s_L} \rceil
Lo=⌈sLLi⌉
其中,
⌈
⌉
\lceil \quad \rceil
⌈⌉表示上取整. 在大部分情况下(特殊情况后面再介绍), 该输出长度使得卷积操作无法在原始输入上进行, 而是需要对输入进行长度上的扩展, 即padding. 扩展的长度为
L
p
=
(
L
0
−
1
)
s
L
+
L
f
−
L
i
L_p = (L_0 - 1) s_L + L_f - L_i
Lp=(L0−1)sL+Lf−Li
事实上, 当
L
i
s
L
\frac{L_i}{s_L}
sLLi为整数时, 即
L
o
=
⌈
L
i
s
L
⌉
=
L
i
s
L
L_o = \lceil \frac{L_i}{s_L} \rceil = \frac{L_i}{s_L}
Lo=⌈sLLi⌉=sLLi, 有
L
p
=
(
L
0
−
1
)
s
L
+
L
f
−
L
i
=
L
f
−
s
L
L_p = (L_0 - 1) s_L + L_f - L_i = L_f - s_L
Lp=(L0−1)sL+Lf−Li=Lf−sL
因此, 当且仅当
L
i
L_i
Li可被
s
L
s_L
sL整除, 且
L
f
=
s
L
L_f = s_L
Lf=sL, 即滑动步长与卷积核的长度相等时, padding的长度为零.
在得到padding的长度后, 除长度为0的情况外, 可分为奇数与偶数两种情况, 这两种情况下输入左右两侧添加的元素数量规则如下.
-
L
p
L_p
Lp为偶数
这种情况比较简单, 左右填充相同数量的元素, 即
L p l = L p r = L p 2 L_{pl} = L_{pr} = \frac{L_p}{2} Lpl=Lpr=2Lp -
L
p
L_p
Lp为奇数
当 L p L_p Lp为奇数时, 遵循左奇右偶的原则, 即
{ L p l = n 1 L p r = n 2 \begin{cases} L_{pl} = n_1 \\ L_{pr} = n_2 \end{cases} {Lpl=n1Lpr=n2
其中 n 1 n_1 n1为奇数, n 2 n_2 n2为偶数且有 n 1 + n 2 = L p n_1+n_2=L_p n1+n2=Lp
未完待续