前言
nn.AdaptiveAvgPool2d(output_size)
函数作用:自适应进行平均池化。不用管输入、stride、padding,函数参数只有输出大小,其他的这个函数帮你搞定。
问题就是,我想知道他是咋搞定的?
1 函数的使用
先把例子摆上来:
input = torch.randn(20, 3, 10, 9)
m = nn.AdaptiveAvgPool2d((5, 7))
output = m(input)
1.1 输入输出
- 输入 input 应为:
(N, C, H_in, W_in)
或(C, H_in W_in)
。这里的 N 表示batch_size,C 表示通道数量。 - 输出 output 为:
(N, C, S_0, S_1)
或(C, S_0, S_1)
,这里 C 不会改变。
1.2 写法
假设输入是input = torch.randn(20, 3, 10, 9)
他的参数有三种写法:
- 如果目标输出size是 5x7:
m = nn.AdaptiveAvgPool2d((5, 7))
- 如果目标输出size是7x7,即长宽一样,就可以写成:
m = nn.AdaptiveAvgPool2d(7)
- 如果目标输出size是10x7,即某一边与输入一样,就可以写成
m = nn.AdaptiveAvgPool2d((None, 7))
2 函数是咋自适应的?
2.1 结论
2.1.1 input size 可以整除 output size
o
u
t
p
u
t
=
i
n
p
u
t
+
2
∗
p
a
d
d
i
n
g
−
k
e
r
n
e
l
s
t
r
i
d
e
+
1
output = \frac{input+2*padding -kernel}{stride}+1
output=strideinput+2∗padding−kernel+1
其中
p
a
d
d
i
n
g
=
0
、
s
t
r
i
d
e
=
i
n
p
u
t
o
u
t
p
u
t
,
k
e
r
n
e
l
=
i
n
p
u
t
−
(
o
u
t
p
u
t
−
1
)
∗
s
t
r
i
d
e
padding=0、stride=\frac{input}{output},kernel=input-(output-1)*stride
padding=0、stride=outputinput,kernel=input−(output−1)∗stride
举例:input size = 6*6,output = 2*3
计算:padding = 0、stride为3和2、kernel size = 3*2
代码验证:
m = nn.AdaptiveAvgPool2d((2, 3))
temp = torch.tensor([1.0,2,3,4,5,6,7,8,9,0,
1.0,2,3,4,5,6,7,8,9,0,
1.0,2,3,4,5,6,7,8,9,0,
1.0,2,3,4,5,6])
input = temp.reshape(1,6,6)
print("input1")
print(input)
output = m(input)
print("output1")
print(output)
2.1.2 不能整除的时候
自适应公式是这样的:
i 从0开始:
K
i
=
c
e
i
l
(
(
i
+
1
)
∗
i
n
p
u
t
o
u
t
p
u
t
)
−
f
l
o
o
r
(
i
∗
i
n
p
u
t
o
u
t
p
u
t
)
K_i=ceil((i+1)*\frac{input}{output})-floor(i*\frac{input}{output})
Ki=ceil((i+1)∗outputinput)−floor(i∗outputinput)
S i = f l o o r ( ( i + 1 ) ∗ i n p u t o u t p u t ) − f l o o r ( i ∗ i n p u t o u t p u t ) S_i=floor((i+1)*\frac{input}{output})-floor(i*\frac{input}{output}) Si=floor((i+1)∗outputinput)−floor(i∗outputinput)
上述公式由源码推导,实际代码中并没有去计算核大小和步长,因为核大小和步长是在不算变化的。
举例解释一波:
假设我们输入size是1维的14,我们想要的输出的size是4,
14/4=3.5
那么我们核大小就为向上取整为4,步长随之而变
输出的size改为3,
14/3=4.666
那么我们核大小就为向上取整为5,步长随之而变
2.2 推导
pytorch官网代码
参考连接