class_docstr: illustration of a minimal bifpn unit P7_0 ------------------------->
  P7_2 -------->
  
  |-------------|                ↑                  ↓                |
  P6_0 ---------> P6_1 ---------> P6_2 -------->
  |-------------|--------------↑ ↑                  ↓                | P5_0
  ---------> P5_1 ---------> P5_2 -------->    |-------------|--------------↑
  ↑                  ↓                | P4_0 ---------> P4_1 ---------> P4_2
  -------->    |-------------|--------------↑ ↑
  |--------------↓ | P3_0 -------------------------> P3_2 -------->
class_docstr_tok: ["illustration","of","a","minimal","bifpn","unit","P7_0","--","--","--","--","--","--","--","--","--","--","--","--","-",">","P7_2","--","--","--","--",">","|","--","--","--","--","--","--","-|","\u2191","\u2193","|","P6_0","--","--","--","--","-",">","P6_1","--","--","--","--","-",">","P6_2","--","--","--","--",">","|","--","--","--","--","--","--","-|","--","--","--","--","--","--","--","\u2191","\u2191","\u2193","|","P5_0","--","--","--","--","-",">","P5_1","--","--","--","--","-",">","P5_2","--","--","--","--",">","|","--","--","--","--","--","--","-|","--","--","--","--","--","--","--","\u2191","\u2191","\u2193","|","P4_0","--","--","--","--","-",">","P4_1","--","--","--","--","-",">","P4_2","--","--","--","--",">","|","--","--","--","--","--","--","-|","--","--","--","--","--","--","--","\u2191","\u2191","|","--","--","--","--","--","--","--","\u2193","|","P3_0","--","--","--","--","--","--","--","--","--","--","--","--","-",">","P3_2","--","--","--","--",">"]
code: def __init__(
      self,
      in_channels: List[int],
      out_channels: int,
      num_outs: int,
      repeat_times: int = 2,
      start_level: int = 0,
      end_level: int = -1,
      add_extra_convs: bool = False,
      relu_before_extra_convs: bool = False,
      no_norm_on_lateral: bool = False,
      conv_cfg: OptConfigType = None,
      norm_cfg: OptConfigType = None,
      act_cfg: OptConfigType = None,
      laterial_conv1x1: bool = False,
      upsample_cfg: ConfigType = dict(mode="nearest"),
      pool_cfg: ConfigType = dict(),
      init_cfg: MultiConfig = dict(
          type="Xavier", layer="Conv2d", distribution="uniform"
      ),
  ):
      super().__init__(init_cfg=init_cfg)
      assert isinstance(in_channels, list)
      self.in_channels = in_channels
      self.out_channels = out_channels
      self.num_ins = len(in_channels)
      self.num_outs = num_outs
      self.relu_before_extra_convs = relu_before_extra_convs
      self.no_norm_on_lateral = no_norm_on_lateral
      self.upsample_cfg = upsample_cfg.copy()
      self.repeat_times = repeat_times
      if end_level == -1 or end_level == self.num_ins - 1:
          self.backbone_end_level = self.num_ins
          assert num_outs >= self.num_ins - start_level
      else:
          # if end_level is not the last level, no extra level is allowed
          self.backbone_end_level = end_level + 1
          assert end_level < self.num_ins
          assert num_outs == end_level - start_level + 1
      self.start_level = start_level
      self.end_level = end_level
      self.add_extra_convs = add_extra_convs
  
      self.lateral_convs = nn.ModuleList()
      self.extra_convs = nn.ModuleList()
      self.bifpn_convs = nn.ModuleList()
      for i in range(self.start_level, self.backbone_end_level):
          if in_channels[i] == out_channels:
              l_conv = nn.Identity()
          else:
              l_conv = ConvModule(
                  in_channels[i],
                  out_channels,
                  1,
                  conv_cfg=conv_cfg,
                  norm_cfg=norm_cfg,
                  bias=True,
                  act_cfg=act_cfg,
                  inplace=False,
              )
          self.lateral_convs.append(l_conv)
  
      for _ in range(repeat_times):
          self.bifpn_convs.append(
              BiFPNLayer(
                  channels=out_channels,
                  levels=num_outs,
                  conv_cfg=conv_cfg,
                  norm_cfg=norm_cfg,
                  act_cfg=act_cfg,
                  pool_cfg=pool_cfg,
              )
          )
  
      # add extra conv layers (e.g., RetinaNet)
      extra_levels = (
          num_outs - self.backbone_end_level + self.start_level
      )
      if add_extra_convs and extra_levels >= 1:
          for i in range(extra_levels):
              if i == 0:
                  in_channels = self.in_channels[
                      self.backbone_end_level - 1
                  ]
              else:
                  in_channels = out_channels
              if in_channels == out_channels:
                  extra_fpn_conv = nn.MaxPool2d(
                      kernel_size=3, stride=2, padding=1
                  )
              else:
                  extra_fpn_conv = nn.Sequential(
                      ConvModule(
                          in_channels=in_channels,
                          out_channels=out_channels,
                          kernel_size=1,
                          norm_cfg=norm_cfg,
                          act_cfg=act_cfg,
                      ),
                      nn.MaxPool2d(kernel_size=3, stride=2, padding=1),
                  )
              self.extra_convs.append(extra_fpn_conv)
  
file_path: mmocr/projects/ABCNet/abcnet/model/bifpn.py
imports: from typing import List
  import torch
  import torch.nn
  import torch.nn.functional
  from mmcv.cnn import ConvModule
  from mmengine.model import BaseModule
  from mmocr.registry import MODELS
  from mmocr.utils import ConfigType, MultiConfig, OptConfigType
label_desc: Use image node_id 1 to create a new BiFPN object from inherited base classes: BaseModule with example: obj = BiFPN(in_channels, out_channels, num_outs, repeat_times, start_level, end_level, add_extra_convs, relu_before_extra_convs, no_norm_on_lateral, conv_cfg, norm_cfg, act_cfg, laterial_conv1x1, upsample_cfg, pool_cfg, init_cfg)