卷积,想必冲浪在一线的大家伙们都已经耳熟能详了,自从深度学习火爆全网之后,大家都在学习一线知识,那么今天想来讲讲关于Pytorch这个深度学习框架下的nn.Conv2d的group这个参数。
group这个参数是为分组卷积而创造出来的,分组卷积的好处呢?就是减少参数量,还能够得到更多的feature map。
这篇文章具体是想探讨一下分组卷积和普通的卷积之后的结果是否相同呢?
首先先来说一下答案:当参与卷积的卷积核是一样的时候,结果是一样,否则则是不一样的。
诶诶诶,先别着急喷,这里我想表达的意思,您可能还不够理解,请接着往下看吧。
关于group这个参数,官网给的解释是这样子的。
大意是什么呢?大概是当groups=1的时候,假设此时 输入的通道数为n,输出的通道数为m,那么理解为把输入的通道分成1组(不分组),每一个输出通道需要在所有的输入通道上做卷积,也就是一种参数共享的局部全连接。
如果把groups改成2,可以理解为把 输入的通道分成两组,此时每一个输出通道只需要在其中一组上做卷积。
如果groups=in_channels,也就是把 输入的通道分成in_channels组(每一组也就一个通道),此时每一个输出通道只需要在其中一个输入通道上做卷积。
不太理解吧?
假如group=2的话,就是把输入通道一分为二,比如我现在的输入格式为 2 ∗ 3 ∗ 3 2*3*3 2∗3∗3的话,现在就是将输入改为 1 ∗ 3 ∗ 3 1*3*3 1∗3∗3,同样的我对应的卷积核也会变为原来通道的一半。
那分组卷积和普通卷积的结果还会不会相同呢?
看下面的代码吧。
import torch
import torch.nn as nn
from torch.autograd import Variable
x=torch.FloatTensor([[1,2,3],[4,5,6],[7,8,9],
[1,2,3],[4,5,6],[7,8,9]]).view(1,2,3,3)
//输入X是通道数为2的3*3矩阵。
x = Variable(x)
conv1 = nn.Conv2d(in_channels=2,
out_channels=2,
kernel_size=3,
stride=1,
padding=0,
groups=1,
bias=False) //conv1普通卷积
conv2 = nn.Conv2d(in_channels=2,
out_channels=2,
kernel_size=3,
stride=1,
padding=0,
groups=2,
bias=False) //conv2是分组卷积
print(conv1.weight.data.size())
print(conv2.weight.data.size())
conv1.weight.data = torch.FloatTensor([[[[1,2,3],[4,5,6],[7,8,9]],
[[9,8,7],[6,5,4],[3,2,1]]],
[[[1,2,3],[4,5,6],[7,8,9]],
[[9,8,7],[6,5,4],[3,2,1]]]])
conv2.weight.data = torch.FloatTensor([[[[1,2,3],[4,5,6],[7,8,9]]],
[[[9,8,7],[6,5,4],[3,2,1]]]] )
print(conv1.weight.data)
print(conv2.weight.data)
output=conv1(x)
print(output)
output=conv2(x)
print(output)
可以从前两行,在conv的配置相同的情况下,选择分组卷积的话,他们的卷积核的大小就已经不一样了。
一个是torch.Size([2, 2, 3, 3])
分组卷积的则是torch.Size([2, 1, 3, 3])
可以明显的看到分组卷积的通道更少,从这里就能直观的看出,分组卷积它是沿着通道数分割成n份。
可以看到卷积核就已经发生了明显的变化,所以最终卷积的结果肯定是不同的,所以在用同一个卷积核的情况下,普通卷积的结果肯定是和分组卷积的结果是不同的。(因为分组卷积的卷积核只是普通卷积的卷积核的一部分。)
(所以一般情况是不同的,并且对应的情况一般是,这分成的n个组卷积之后的结果 的 对应点相加,才等于普通卷积卷积出的结果。)