近期由于又重新接触到pytorch转caffe的相关任务(gempool)。发现BN并不是caffe底层代码就已经写了一个BN的实现,而是在prototxt用一些不同的算子组合成BN层。
这一点仿佛为我打开了新世界的大门,觉得还挺神奇的,所以先写一篇来看看gempool公式,并进行对应的prototxt的实现吧。加深一下理解。
1.分析
Generalized Mean Pooling Explained | Papers With Codehttps://paperswithcode.com/method/generalized-mean-pooling看下面的公式,可能会云里雾里,但是会发现有相同的参数p,一个时power(p),一个是power(1/p)。
对应的代码(https://github.com/JDAI-CV/fast-reid/blob/master/fastreid/layers/pooling.py#L50),上面公式的代码表示:
class GeneralizedMeanPooling(nn.Module):
r"""Applies a 2D power-average adaptive pooling over an input signal composed of several input planes.
The function computed is: :math:`f(X) = pow(sum(pow(X, p)), 1/p)`
- At p = infinity, one gets Max Pooling
- At p = 1, one gets Average Pooling
The output is of size H x W, for any input size.
The number of output features is equal to the number of input planes.
Args:
output_size: the target output size of the image of the form H x W.
Can be a tuple (H, W) or a single H for a square image H x H
H and W can be either a ``int``, or ``None`` which means the size will
be the same as that of the input.
"""
def __init__(self, norm=3, output_size=(1, 1), eps=1e-6, *args, **kwargs):
super(GeneralizedMeanPooling, self).__init__()
assert norm > 0
self.p = float(norm)
self.output_size = output_size
self.eps = eps
def forward(self, x):
x = x.clamp(min=self.eps).pow(self.p)
return F.adaptive_avg_pool2d(x, self.output_size).pow(1. / self.p)
def __repr__(self):
return self.__class__.__name__ + '(' \
+ str(self.p) + ', ' \
+ 'output_size=' + str(self.output_size) + ')'
2.实现
由上面知道基本是两个power与一个avgpool夹心饼干的组合。得到一个gempool。如果是固定参数的话,就计算好就行了,分数部分需要修改为小数。
那以上面的代码为例,p=3,则1/p≈0.3334。
layer {
name: "gem_power1"
type: "Power"
bottom: "relu_blob1"
top: "power_blob1"
power_param {
power: 2
scale: 1
shift: 0
}
}
layer {
name: "avgpool1"
type: "Pooling"
bottom: "power_blob1"
top: "avgpool_blob1"
pooling_param {
pool: AVE
global_pooling: true
}
}
layer {
name: "gem_power2"
type: "Power"
bottom: "avgpool_blob1"
top: "power_blob2"
power_param {
power: 0.3334
scale: 1
shift: 0
}
}