乐趣区

关于pytorch:经验分享pytorch-与-darknet-计算卷积输出-shape-方式对比

欢送关注我的公众号 [极智视界],回复 001 获取 Google 编程标准

O_o>_<   o_OO_o~_~o_O

  本文记录了 pytorch 与 darknet 计算卷积输入 shape 形式比照,两者有一些区别。

   卷积算子是深度学习中最罕用的算子,在神经网络中,往往须要波及到算子 shape 形态的推导,这里次要说一下 cov 层的 shape 推导,拿 pytorch 和 darknet 进行比照。

1、pytorch 卷积输入 shape 推导

   看源码,答案在 torch/nn/modules/conv.py 脚本 class Conv2d(_ConvNd) 类的正文中:

Shape:
    - Input: :math:`(N, C_{in}, H_{in}, W_{in})`
    - Output: :math:`(N, C_{out}, H_{out}, W_{out})` where

      .. math::
          H_{out} = \left\lfloor\frac{H_{in}  + 2 \times \text{padding}[0] - \text{dilation}[0]
                    \times (\text{kernel\_size}[0] - 1) - 1}{\text{stride}[0]} + 1\right\rfloor

      .. math::
          W_{out} = \left\lfloor\frac{W_{in}  + 2 \times \text{padding}[1] - \text{dilation}[1]
                    \times (\text{kernel\_size}[1] - 1) - 1}{\text{stride}[1]} + 1\right\rfloor

  以上的计算公式为 LaTeX 格局,这是一种基于 TEX 的排版系统,由美国计算机学家莱斯利 - 兰伯特创造,利用这种格局,可能疾速生成简单表格和数学公式。不过这种格局对于咱们来说可读性比拟差,这里用富本编辑器的 公式 性能转换一下,来看 H_{out}:

  这里思考了空洞卷积的膨胀系数,如果把 dilation 去掉,shape 推导会是这样的:

  以上是 pytorch 中对于卷积 shape 的推导形式,上面来看一下 darknet 中的状况。

2、darknet 卷积输入 shape 推导

   同样看源码,在 parser.c 中有:

int size = option_find_int(options, "size", 1);
int pad = option_find_int_quiet(options, "pad", 0);
int padding = option_find_int_quiet(options, "padding", 0);
if(pad) padding = size/2;

   其中 option_find_int 和 option_find_int_quiet 均为链表查找函数,这里有点不一样的中央,能够把 pad 了解为填充标记位,理论填充值为 padding,从以上代码能够看出理论用的 padding 并不是间接从模型文件中读出来的 padding,而是通过标记位 pad 判断解决后失去的 padding。

   如上解决后再进行卷积输入 shape 的计算,代码在 convolutional_layer.c 中:

/// 调用接口
/// int out_h = convolutional_out_height(l);
/// int out_w = convolutional_out_width(l);

int convolutional_out_height(convolutional_layer l)
{return (l.h + 2*l.pad - l.size) / l.stride_y + 1;
}

int convolutional_out_width(convolutional_layer l)
{return (l.w + 2*l.pad - l.size) / l.stride_x + 1;
}

   将以上的 out_h 计算过程可视化一下:

  看到这里可能还有一个纳闷,怎么间接用的是 l.pad,而不是 l.padding 呢,答案在这里:

l.pad = padding;

   这样就说得通了,再来看个案例,如下图:

  来看框出来的层,以 n c h w 布局的话输出为 [n , 16, 256, 256],从可视化看到通过这个卷积后的 shape 仍旧为 [n, 16, 256, 256],如果咱们以 pytorch 的计算形式:Hout = (Hin + 2 * padding - (size - 1)- 1) / stride + 1 来计算的话,你可能会认为 pad 即为 padding,则 Hout = (256 + 2 - (1 - 1) -1) / 1 + 1 = 258,此时失去的后果显然不对,故这种计算形式存在问题。咱们改用 darknet 中的计算形式,即把 pad 当作标记位,先计算 padding,这里算子参数里没有写 padding,则令 padding = 0,计算过程如下:

size = 1
padding = 0
pad = 1
    
/// if(pad) padding = size / 2;
padding = 1 / 2 = 0

/// Hout = (Hin + 2 * padding - size) / stride + 1
Hout = (256 + 2 * 0 - 1) + 1 = 256

   对于 C 语言中的 / 是一般的除法,失去的为浮点数时,间接把小数点前面的舍去,即向下取整。

  这样后果就能对起来了。

   以上分享了 pytorch 和 darknet 中对于卷积输入 shape 的计算形式比照,也是容易碰到的小坑,心愿我的分享对你有一点帮忙。


【公众号传送】
《【教训分享】pytorch 与 darknet 计算卷积输入 shape 形式比照》

退出移动版