前言
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官网代码
参考连接