class_docstr: Feature Pyramid Network, see https://arxiv.org/abs/1612.03144
  
  Args:
      in_channels (list[int]): input channels of each level which can be 
          derived from the output shape of backbone by from_config
      out_channel (int): output channel of each level
      spatial_scales (list[float]): the spatial scales between input feature
          maps and original input image which can be derived from the output 
          shape of backbone by from_config
      has_extra_convs (bool): whether to add extra conv to the last level.
          default False
      extra_stage (int): the number of extra stages added to the last level.
          default 1
      use_c5 (bool): Whether to use c5 as the input of extra stage, 
          otherwise p5 is used. default True
      norm_type (string|None): The normalization type in FPN module. If 
          norm_type is None, norm will not be used after conv and if 
          norm_type is string, bn, gn, sync_bn are available. default None
      norm_decay (float): weight decay for normalization layer weights.
          default 0.
      freeze_norm (bool): whether to freeze normalization layer.  
          default False
      relu_before_extra_convs (bool): whether to add relu before extra convs.
          default False
      
class_docstr_tok: ["Feature","Pyramid","Network",",","see","https",":","\/\/arxiv.org\/abs\/1612.03144","Args",":","in_channels","(","list","[","int","]",")",":","input","channels","of","each","level","which","can","be","derived","from","the","output","shape","of","backbone","by","from_config","out_channel","(","int",")",":","output","channel","of","each","level","spatial_scales","(","list","[","float","]",")",":","the","spatial","scales","between","input","feature","maps","and","original","input","image","which","can","be","derived","from","the","output","shape","of","backbone","by","from_config","has_extra_convs","(","bool",")",":","whether","to","add","extra","conv","to","the","last","level",".","default","False","extra_stage","(","int",")",":","the","number","of","extra","stages","added","to","the","last","level",".","default","1","use_c5","(","bool",")",":","Whether","to","use","c5","as","the","input","of","extra","stage",",","otherwise","p5","is","used",".","default","True","norm_type","(","string|None",")",":","The","normalization","type","in","FPN","module",".","If","norm_type","is","None",",","norm","will","not","be","used","after","conv","and","if","norm_type","is","string",",","bn",",","gn",",","sync_bn","are","available",".","default","None","norm_decay","(","float",")",":","weight","decay","for","normalization","layer","weights",".","default","0.","freeze_norm","(","bool",")",":","whether","to","freeze","normalization","layer",".","default","False","relu_before_extra_convs","(","bool",")",":","whether","to","add","relu","before","extra","convs",".","default","False"]
code: def forward(self, body_feats):
      laterals = []
      num_levels = len(body_feats)
      for i in range(num_levels):
          laterals.append(self.lateral_convs[i](body_feats[i]))
  
      for i in range(1, num_levels):
          lvl = num_levels - i
          upsample = F.interpolate(
              laterals[lvl],
              scale_factor=2.0,
              mode="nearest",
          )
          laterals[lvl - 1] += upsample
  
      fpn_output = []
      for lvl in range(num_levels):
          fpn_output.append(self.fpn_convs[lvl](laterals[lvl]))
  
      if self.extra_stage > 0:
          # use max pool to get more levels on top of outputs (Faster R-CNN, Mask R-CNN)
          if not self.has_extra_convs:
              assert (
                  self.extra_stage == 1
              ), "extra_stage should be 1 if FPN has not extra convs"
              fpn_output.append(
                  F.max_pool2d(fpn_output[-1], 1, stride=2)
              )
          # add extra conv levels for RetinaNet(use_c5)/FCOS(use_p5)
          else:
              if self.use_c5:
                  extra_source = body_feats[-1]
              else:
                  extra_source = fpn_output[-1]
              fpn_output.append(
                  self.fpn_convs[num_levels](extra_source)
              )
  
              for i in range(1, self.extra_stage):
                  if self.relu_before_extra_convs:
                      fpn_output.append(
                          self.fpn_convs[num_levels + i](
                              F.relu(fpn_output[-1])
                          )
                      )
                  else:
                      fpn_output.append(
                          self.fpn_convs[num_levels + i](fpn_output[-1])
                      )
      return fpn_output
  
file_path: PaddleDetection/ppdet/modeling/necks/fpn.py
imports: import paddle.nn
  import paddle.nn.functional
  from paddle import ParamAttr
  from paddle.nn.initializer import XavierUniform
  from ppdet.core.workspace import register, serializable
  from ppdet.modeling.layers import ConvNormLayer
  from ..shape_spec import ShapeSpec
label_desc: Use image node_id 3 for calling the FPN obj's underlying member method code with example usage: obj.forward(body_feats) and returns: fpn_output