Involution: Inverting the Inherence of Convolution for Visual Recognition

Involution伪代码

image
image
上面是文章中的两个图片,第一幅图片是第二张图片的伪代码。

普通的卷积与Involution

普通的卷积会使用一个固定的卷积核在原图像上进行滑动,然后做乘积后进行相加,得到卷积后的feature map,Involution还是滑动窗口,只不过它的kernel是特殊的由它自己生成。

如何生成卷积核

观察第二张图片,是由其某个像素生成(H为生成的kernel),结合代码,首先是先利用r(控制通道数量的因子,r也可以设置为1,增加这个因子我的理解是为了减少冗余,通道之间是有冗余的)reduce将通道数量减少,然后expan将通道延展为kernel然后与原位置的像素邻域做乘积(就像卷积一样),然后生成上图那个五颜六色的长方体,最后将乘积后的邻域值进行相加,最后又成为了一个像素。

代码中是如何做的

x_unfolded = unfold(x) # B,CxKxK,HxW
x_unfolded = x_unfolded.view(B, G, C//G, K*K, H, W)
这两行表示的是将原map进行unfold,
kernel = span(reduce(o(x))) # B,KxKxG,H,W
kernel = kernel.view(B, G, K*K, H, W).unsqueeze(2)
这两行是生成kernel,这里比较难理解的是为什么生成这种形状。原因是上面我们用unfold进行滑动,使用的滑动窗口大小为k,这里也是按照unfold后的矩阵进行生成的,然后再做乘积和加法,不就是相当于一边做滑动一边计算乘积(类似卷积),这样的计算相当于所有位置同时做卷积,只不过卷积核是特殊的。
out = mul(kernel, x_unfolded).sum(dim=3)
最后将所有运算乘法后的窗口,窗口内的值相加得到最终的involution后的结果。

什么是unfold

普通的卷积是滑动kernel并且计算,但是unfold是只滑动不计算,留待用生成的kernel进行计算,相关参考:https://blog.csdn.net/weixin_44076434/article/details/106545037

Invlution意义

后续。。。

posted @ 2021-06-18 16:48  LiangLiangAA  阅读(326)  评论(0编辑  收藏  举报
theme: { name: 'geek', avatar: '', headerBackground: '' // ... },