理解tf.pad()及tensorflow卷积中的padding方式(“SAME”和“VALID”)

最近细看了一下yolov3的代码,对其中的填充语法小结一下,方便之后回顾复习。

首先说一下填充的作用:

       填充(即代码中的padding),就是在矩阵的周围补0,一般用于进行卷积操作之前,使得每个输入像素都能作为卷积核窗口的中心。

以下面这段代码为契机首先理解tf.pad():

def _fixed_padding(inputs, kernel_size):
    #这里的inputs format为'NHWC'
    pad_total = kernel_size - 1
    pad_beg = pad_total // 2
    pad_end = pad_total - pad_beg

    padded_inputs = tf.pad(inputs, [[0, 0], [pad_beg, pad_end],
                                    [pad_beg, pad_end], [0, 0]], mode='CONSTANT')
    return padded_inputs

一、tf.pad()理解:

参数解释:

inputs:要填充的输入张量,如yolov3网络中的输入图像format为:N*H*W*C(N:batch数量,H:高,W:宽,C:通道数),eg:2*416*416*1

第二个参数表示填充顺序:比如以上代码中的这种形式:[[0, 0], [pad_beg, pad_end], [pad_beg, pad_end], [0, 0]],代表在每一个"维度"上填充多少行或多少列,“维度”和输入张量的“维度”一样,这里的维度可能与传统理解的维度不一样,这里的“维度”是指比如输入inputs大小是2*416*416*1,就是4维,然后填充顺序也要保证有四维,类似于一个二维矩阵,行数就是与输入inputs维度要相同,这里是4,列数固定就是2,即大概这种形状:[[ ,],[ ,],[ ,],[ ,]],然后第一行就对应输入inputs中的2这个维度,第二行对应输入inputs中的416(H)这个维度,第三行对应输入inputs中的416(W)这个维度,第四行对应输入inputs中的1这个维度。

mode:'CONSTANT',表示用0填充像素值,默认值

例子:比如这里kernel_size=3

那么pad_beg = 1,pad_end = 1,

填充顺序为[[0, 0], [1, 1], [1, 1], [0, 0]],表示的意义是:在batch数量为2的这个维度上,[0,0]表示头和尾填充行或列数为0,就是不填充;在416(H)这个维度上,[1,1]表示头和尾分别都要填充,即最上面填充1行,最下面填充1行;在416(W)这个维度上,[1,1]表示头和尾分别都要填充,即最左边填充1列,最右边填充1列;在1这个维度上,[0,0]表示头和尾填充行或列数为0,就是不填充

所以经过tf.pad()后,张量大小变为418*418(H*W)

 

二、tensorflow卷积中的两种padding方式“SAME”和“VALID”

padding = “SAME”时,输入和输出大小关系如下公式所示:

Noutput = Ninput / s  #输出大小等于输入大小除以步长向上取整,s是步长大小;

padding = “VALID”时,输入和输出大小关系如下公式所示:

Noutput = (Ninput - f + 1) / s  #输出大小等于输入大小减去滤波器大小加上1,最后再除以步长,f为滤波器的大小,s是步长大小

通用的输入特征图与输出特征图大小之间的关系:Noutput = (Ninput - f +2 * padding) / s + 1 #f为滤波器的大小,s是步长大小,padding是填充数,这个公式一般是已知padding数,来求输出特征图大小,与上面两个公式的区别:利用上面两个公式可计算出输出特征图大小,然后通过这个通用公式可计算出padding 0 的个数

 

Winograd算法是一种加速卷积计算的方法,它通过将输入数据卷积核转换为小块的矩阵乘法来实现加速。在深度可分离卷积中,每个卷积层都由一个深度可分离卷积一个点卷积组成。因此,我们可以使用Winograd算法来加速深度可分离卷积中的深度可分离卷积。 具体来说,我们可以将深度可分离卷积的深度可分离部分转换为Winograd算法中的小块矩阵乘法。假设输入数据为$X\in R^{H\times W\times C_{in}}$,卷积核为$K\in R^{K_h\times K_w\times C_{in}\times C_{out}}$,其中$C_{in}$$C_{out}$分别表示输入数据输出数据的通道数。我们可以将输入数据卷积核都转换为$G\times G$的小块矩阵,其中$G$是Winograd算法中的常数。 具体来说,我们可以将输入数据转换为$B\in R^{G\times G\times C_{in}\times N}$,其中$N=\frac{(H-K_h+1)\times (W-K_w+1)}{G^2}$是输入数据的块数。然后,我们可以将卷积核转换为$A\in R^{G\times G\times C_{in}\times C_{out}}$。接下来,我们可以计算$B$$A$之间的矩阵乘积$BA$,得到输出数据$Y\in R^{H\times W\times C_{out}}$。最后,我们可以通过点卷积来计算深度可分离卷积的点卷积部分。 由于Winograd算法的复杂度较低,因此可以有效地加速深度可分离卷积的计算。同时,使用Winograd算法也可以减少内存占用计算量,提高模型的效率性能。 下面是使用tensorflow实现基于Winograd算法的深度可分离卷积的示例代码: ```python import tensorflow as tf def winograd_depthwise_separable_conv(input, filter, strides, padding='SAME', name=None): with tf.variable_scope(name, default_name='winograd_depthwise_separable_conv'): # Depthwise convolution in_channels = input.get_shape().as_list()[-1] filter_shape = filter.get_shape().as_list() filter = tf.reshape(filter, [filter_shape[0], filter_shape[1], in_channels, 1]) input = tf.expand_dims(input, axis=-2) depthwise_out = tf.nn.depthwise_conv2d(input, filter, strides=[1, 1, 1, 1], padding='VALID') depthwise_out = tf.squeeze(depthwise_out, axis=-2) # Winograd convolution G = 3 B = tf.constant([ [1, 0, 0], [-1/6, -1/6, -1/6], [-1/6, 1/6, -1/6], [1/24, 1/12, 1/6], [1/24, -1/12, 1/6], [0, 0, 1] ], dtype=tf.float32) B = tf.reshape(B, [1, 1, G, G, 1, 6]) B = tf.tile(B, [1, 1, 1, 1, in_channels, 1]) A = tf.transpose(filter, [0, 1, 3, 2]) A = tf.reshape(A, [filter_shape[0], filter_shape[1], 1, in_channels, filter_shape[2]]) A = tf.tile(A, [1, 1, G, 1, 1]) A = tf.reshape(A, [1, 1, G, G, in_channels, filter_shape[2]]) out_shape = tf.stack([tf.shape(input)[0], tf.shape(input)[1], tf.shape(input)[2], filter_shape[2]]) input = tf.pad(input, [[0, 0], [1, 1], [1, 1], [0, 0]], mode='CONSTANT') input = tf.expand_dims(input, axis=-2) winograd_out = tf.nn.conv2d(input, B, strides=[1, strides, strides, 1], padding='VALID') winograd_out = tf.squeeze(winograd_out, axis=-2) winograd_out = tf.transpose(winograd_out, [0, 1, 2, 4, 3]) winograd_out = tf.reshape(winograd_out, [-1, G, G, in_channels]) winograd_out = tf.matmul(winograd_out, A) winograd_out = tf.reshape(winograd_out, out_shape) # Pointwise convolution pointwise_out = tf.layers.conv2d(winograd_out, filter_shape[3], [1, 1], strides=[1, 1], padding='SAME') return pointwise_out ``` 在这个实现中,我们首先使用tensorflow的`depthwise_conv2d`函数来实现深度可分离卷积的深度可分离部分。然后,我们使用Winograd算法来实现深度可分离卷积的深度可分离部分。具体来说,我们将输入数据卷积核都转换为$G\times G$的小块矩阵,并计算它们之间的矩阵乘积。最后,我们使用点卷积来实现深度可分离卷积的点卷积部分。 总之,基于tensorflow,使用Winograd算法改进深度可分离卷积是一种有效的加速深度学习模型的方法。通过使用Winograd算法,我们可以大大减少深度可分离卷积的计算复杂度,提高模型的效率性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值