欢送关注我的公众号 [极智视界],回复 001 获取 Google 编程标准
O_o
>_<
o_O
O_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 形式比照》