text: #!/usr/bin/env python
  # coding: utf-8
  
  import torch
  import torch.nn as nn
  
  from ..builder import NECKS
  
  @NECKS.register_module()
  class YOLOV3Neck_lite(nn.Module):
      """The neck of YOLOV3.
  
      It can be treated as a simplified version of FPN. It
      will take the result from Darknet backbone and do some upsampling and
      concatenation. It will finally output the detection result.
  
      Note:
          The input feats should be from top to bottom.
              i.e., from high-lvl to low-lvl
          But YOLOV3Neck will process them in reversed order.
              i.e., from bottom (high-lvl) to top (low-lvl)
  
      Args:
          num_scales (int): The number of scales / stages.
          in_channels (int): The number of input channels.
          out_channels (int): The number of output channels.
          conv_cfg (dict): Config dict for convolution layer. Default: None.
          norm_cfg (dict): Dictionary to construct and config norm layer.
              Default: dict(type='BN', requires_grad=True)
          act_cfg (dict): Config dict for activation layer.
              Default: dict(type='LeakyReLU', negative_slope=0.1).
      """
  
      def __init__(self,
                   num_scales,
                   in_channels,
                   out_channels,
                   conv_cfg=None,
                   norm_cfg=dict(type='BN', requires_grad=True),
                   act_cfg=dict(type='LeakyReLU', negative_slope=0.1)):
          super(YOLOV3Neck_lite, self).__init__()
          assert (num_scales == len(in_channels) == len(out_channels))
          self.num_scales = num_scales
          self.in_channels = in_channels
          self.out_channels = out_channels
  
          # shortcut
          cfg = dict(conv_cfg=conv_cfg, norm_cfg=norm_cfg, act_cfg=act_cfg)
  
          '''
          # To support arbitrary scales, the code looks awful, but it works.
          # Better solution is welcomed.
          self.detect1 = DetectionBlock(in_channels[0], out_channels[0], **cfg)
          for i in range(1, self.num_scales):
              in_c, out_c = self.in_channels[i], self.out_channels[i]
              self.add_module(f'conv{i}', ConvModule(in_c, out_c, 1, **cfg))
              # in_c + out_c : High-lvl feats will be cat with low-lvl feats
              self.add_module(f'detect{i+1}',DetectionBlock(in_c + out_c, out_c, **cfg))
          '''
          
      def forward(self, feats):
          '''
          assert len(feats) == self.num_scales
  
          # processed from bottom (high-lvl) to top (low-lvl)
          outs = []
          out = self.detect1(feats[-1])
          outs.append(out)
   
          for i, x in enumerate(reversed(feats[:-1])):
              conv = getattr(self, f'conv{i+1}')
              tmp = conv(out)
  
              # Cat with low-lvl feats
              tmp = F.interpolate(tmp, scale_factor=2)
              tmp = torch.cat((tmp, x), 1)
  
              detect = getattr(self, f'detect{i+2}')
              out = detect(tmp)
              outs.append(out)
          '''
          outs = []
          for i in range(len(feats)):
              outs.append(feats[len(feats) - i - 1])
          return outs
   
      def init_weights(self):
          """Initialize the weights of module."""
          # init is done in ConvModule
          pass