简单易懂的利用F.conv2d函数进行卷积的前向传播和反向传播

其实你去看pytorch中的nn.Conv2d的源码的时候,你会发现它还是调用的nn.functional.conv2d,如下图所示:
简单易懂的利用F.conv2d函数进行卷积的前向传播和反向传播_第1张图片
显然这在前向传播中我们已经用的非常多了,有时候在跟踪里面会计算template和search的互相关,也是利用F.conv2d函数实现的,本篇文章用生动易懂的方式讲解一下F.conv2d前向传播和反向传播的过程。

前向传播(forward propagation)

官方的参数列表是这样的:

torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1)

  • input – input tensor of shape (minibatch,in_channels,iH,iW)
  • weight – filters of shape(out_channels, i n _ c h a n n e l s g r o u p s \frac {in\_channels}{groups} groupsin_channels,kH,kW)
  • output – output tensor of shape (minibatch,out_channels,oH,oW)

看一下一个例子,假设
简单易懂的利用F.conv2d函数进行卷积的前向传播和反向传播_第2张图片
这里按照卷积的公式和上面的文档就可以容易得出。也可以看下面的图:
其实上面还涉及了分组卷积,把1024的通道数改成了2个512,此时也就有2个512通道的卷积核 f 1 f_{1} f1, f 2 f_{2} f2,分别与 g 1 g_{1} g1, b 1 b_{1} b1, y 1 y_{1} y1 g 2 g_{2} g2, b 2 b_{2} b2, y 2 y_{2} y2卷积得到 g 11 g_{11} g11, b 11 b_{11} b11, y 11 y_{11} y11 g 22 g_{22} g22, b 22 b_{22} b22, y 22 y_{22} y22,这样输出就是3个2通道的19×19的tensor了。
简单易懂的利用F.conv2d函数进行卷积的前向传播和反向传播_第3张图片

反向传播(backward propagation)

前面的前向传播较好理解,不过也是理解下面用F.conv2d实现反向传播的基础,让我们先看一下简单的反向传播例子:

假设有一张1×1的feature map,然后周围padding=2,用4×4的卷积核去卷积,得到一张2×2的输出map

左图中四种不同的颜色的4×4的框表示卷积核滑动窗口在不同的位置,右边是其对应的输出位置,由相同颜色对应。

假设现在得到了一张2×2的上游传过来的梯度map,这时要计算相对于卷积核的梯度,这时我们知道,卷积核和特征feature map之间就是+和×的操作,所以对于卷积核的梯度可以由下图四张4×4的特征值和对应上游梯度位置相乘后相加得到(即图中的土色tensor)

简单易懂的利用F.conv2d函数进行卷积的前向传播和反向传播_第4张图片
那有没有更高效的方法实现上面的四张4×4的特征值和对应上游梯度位置相乘后相加这个操作呢?不难发现,这种相乘相加的操作不就是卷积嘛?再仔细看一眼,发现F.conv2d(feature_map, upstream_gradient)就是最后的图中土色的tensor

那对于一般的情况该怎么操作呢?还是拿上面前向传播的例子举例:
此时我们就需要 g 11 g_{11} g11的上游梯度 G 11 G_{11} G11 g 1 g_{1} g1做卷积得到 f g 1 f_{g1} fg1 g 22 g_{22} g22的上游梯度 G 22 G_{22} G22 g 2 g_{2} g2做卷积得到 f g 2 f_{g2} fg2,以此类推。最后
f g 1 + f b 1 + f y 1 = ∂ f 1 f_{g1}+f_{b1}+f_{y1}=\partial f_{1} fg1+fb1+fy1=f1 f g 2 + f b 2 + f y 2 = ∂ f 2 f_{g2}+f_{b2}+f_{y2}=\partial f_{2} fg2+fb2+fy2=f2
如下图所示的:
简单易懂的利用F.conv2d函数进行卷积的前向传播和反向传播_第5张图片
只不过需要在输入的时候转化一下维度,具体过程可见下面:
在这里插入图片描述
更一般的总结就是

F.conv2d(input, weight, padding=p, groups=g)

  1. forward: when given
    input tensor shape: [B, Cin, iH, iW]
    weight tensor shape: [g, C i n g \frac {Cin}{g} gCin, kH, kW]
    we can get output tensor shape: [B, g, oH, oW]
  2. backward: when given
    input tensor shape: [B, Cin, iH, iW]
    upstream gradient shape: [B, g, oH, oW]
    we can get gradient relative to weight by following:
    2.1 F.conv2d([ C i n g \frac {Cin}{g} gCin, Bg, iH, iW], [Bg,1,oH,oW], groups=Bg, padding=p) ,and get [ C i n g \frac {Cin}{g} gCin,Bg,kH,kW]
    2.2 [ C i n g \frac {Cin}{g} gCin,Bg,kH,kW] view as [ C i n g \frac {Cin}{g} gCin,B, g,kH,kW] and sum along with dim=1, get [ C i n g \frac {Cin}{g} gCin,g,kH,kW]
    2.3 [ C i n g \frac {Cin}{g} gCin,g,kH,kW] re-view as [g, C i n g \frac {Cin}{g} gCin,kH,kW] same shape with weight

你可能感兴趣的:(PyTorch,pytorch)