123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- import paddle
- import paddle.nn.functional as F
- import paddle.nn as nn
- from ppdet.core.workspace import register
- from ..shape_spec import ShapeSpec
- __all__ = ['HRFPN']
- @register
- class HRFPN(nn.Layer):
- """
- Args:
- in_channels (list): number of input feature channels from backbone
- out_channel (int): number of output feature channels
- share_conv (bool): whether to share conv for different layers' reduction
- extra_stage (int): add extra stage for returning HRFPN fpn_feats
- spatial_scales (list): feature map scaling factor
- """
- def __init__(self,
- in_channels=[18, 36, 72, 144],
- out_channel=256,
- share_conv=False,
- extra_stage=1,
- spatial_scales=[1. / 4, 1. / 8, 1. / 16, 1. / 32]):
- super(HRFPN, self).__init__()
- in_channel = sum(in_channels)
- self.in_channel = in_channel
- self.out_channel = out_channel
- self.share_conv = share_conv
- for i in range(extra_stage):
- spatial_scales = spatial_scales + [spatial_scales[-1] / 2.]
- self.spatial_scales = spatial_scales
- self.num_out = len(self.spatial_scales)
- self.reduction = nn.Conv2D(
- in_channels=in_channel,
- out_channels=out_channel,
- kernel_size=1,
- bias_attr=False)
- if share_conv:
- self.fpn_conv = nn.Conv2D(
- in_channels=out_channel,
- out_channels=out_channel,
- kernel_size=3,
- padding=1,
- bias_attr=False)
- else:
- self.fpn_conv = []
- for i in range(self.num_out):
- conv_name = "fpn_conv_" + str(i)
- conv = self.add_sublayer(
- conv_name,
- nn.Conv2D(
- in_channels=out_channel,
- out_channels=out_channel,
- kernel_size=3,
- padding=1,
- bias_attr=False))
- self.fpn_conv.append(conv)
- def forward(self, body_feats):
- num_backbone_stages = len(body_feats)
- outs = []
- outs.append(body_feats[0])
- # resize
- for i in range(1, num_backbone_stages):
- resized = F.interpolate(
- body_feats[i], scale_factor=2**i, mode='bilinear')
- outs.append(resized)
- # concat
- out = paddle.concat(outs, axis=1)
- assert out.shape[
- 1] == self.in_channel, 'in_channel should be {}, be received {}'.format(
- out.shape[1], self.in_channel)
- # reduction
- out = self.reduction(out)
- # conv
- outs = [out]
- for i in range(1, self.num_out):
- outs.append(F.avg_pool2d(out, kernel_size=2**i, stride=2**i))
- outputs = []
- for i in range(self.num_out):
- conv_func = self.fpn_conv if self.share_conv else self.fpn_conv[i]
- conv = conv_func(outs[i])
- outputs.append(conv)
- fpn_feats = [outputs[k] for k in range(self.num_out)]
- return fpn_feats
- @classmethod
- def from_config(cls, cfg, input_shape):
- return {
- 'in_channels': [i.channels for i in input_shape],
- 'spatial_scales': [1.0 / i.stride for i in input_shape],
- }
- @property
- def out_shape(self):
- return [
- ShapeSpec(
- channels=self.out_channel, stride=1. / s)
- for s in self.spatial_scales
- ]
|