Tensorflow学习笔记: tf.nn.conv2d函数与tf.nn.depthwise_conv2d函数

tf.nn.conv2d与depthwise_conv2d函数

  • 参数
  • 计算过程
    • 卷积计算
      • padding = "VALID"
      • padding = "SAME"

参数

首先需要注意的是, 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)} WRHf×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 } IRN×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 } IRN×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} WRHf×Wf×Ci×Co, 卷积操作表示为
O = I ∗ W \mathbf{O} = \mathbf{I} * \mathbf{W} O=IW
根据输入的参数, 卷积操作的具体计算方法可分为"VALID"与"SAME"两种, 我们使用一维卷积来介绍这两种计算过程的区别, 首先定义输入 I \mathbf{I} I 的长度(Length)为 L i L_i Li, 即 I ∈ R L i \mathbf{I} \in \mathbb{R}^{L_i} IRLi, 卷积核为 W ∈ R L f \mathbf{W} \in \mathbb{R}^{L_f} WRLf, 滑动步长为 s L s_L sL.

首先需要注意的是, "VALID"与"SAME"本质上的区别在于输出的大小与输入大小是否相同(即SAME表示的是输出大小与输入大小相同), 而控制这一点的方法则是通过在输入两侧(一维情况是两侧, 二维则是上下左右四侧, 亦可扩展至三维输入中)增加0, 具体过程将在padding = "SAME"的章节中进行分析. 接下来首先介绍padding = "VALID"的情况.

padding = “VALID”

VALID情况的下卷积过程如图所示
Tensorflow学习笔记: tf.nn.conv2d函数与tf.nn.depthwise_conv2d函数_第1张图片
卷积过程从第一个元素开始, 然后根据滑动步长进行滑动. 需要注意的是, 为了使卷积时卷积核对应位置不会超出输入范围, 有时候需要舍弃最后一些元素, 这是由于在卷积时, 最后一次卷积核对应位置的末位索引不能超过输入长度, 即满足下式
( n − 1 ) s L + 1 + ( L f − 1 ) ≤ L i (n-1) s_L + 1 + (L_f -1) \leq L_i (n1)sL+1+(Lf1)Li
即可得到卷积操作的次数 n n n
n = ⌊ L i − L f s L ⌋ + 1 n = \lfloor \frac{L_i - L_f}{s_L} \rfloor + 1 n=sLLiLf+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[(n1)sL+Lf]

padding = “SAME”

SAME情况的卷积过程如图所示
Tensorflow学习笔记: tf.nn.conv2d函数与tf.nn.depthwise_conv2d函数_第2张图片可以看到, 在输入的前后分别添加了一些元素使得卷积过程满足一些条件, 称为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=(L01)sL+LfLi
事实上, 当 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=(L01)sL+LfLi=LfsL
因此, 当且仅当 L i L_i Li可被 s L s_L sL整除, 且 L f = s L L_f = s_L Lf=sL, 即滑动步长与卷积核的长度相等时, padding的长度为零.

在得到padding的长度后, 除长度为0的情况外, 可分为奇数与偶数两种情况, 这两种情况下输入左右两侧添加的元素数量规则如下.

  1. 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
  2. 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

未完待续

你可能感兴趣的:(Python,Tensorflow,Python)