text: import torch
  import torch.nn as nn
  import torch.nn.functional as F
  from collections import OrderedDict
  from layers.grid_attention_layer import GridAttentionBlock3D
  from networks_other import init_weights
  import math
  
  __all__ = [
      'DenseNet', 'densenet121_twochanel_cam', 'densenet169', 'densenet201', 'densenet264'
  ]
  
  
  def densenet121_twochanel_cam(**kwargs):
      model = DenseNet(
          num_init_features=64,
          growth_rate=32,
          block_config=(6, 12, 24, 16),
          **kwargs)
      return model
  
  
  def densenet169(**kwargs):
      model = DenseNet(
          num_init_features=64,
          growth_rate=32,
          block_config=(6, 12, 32, 32),
          **kwargs)
      return model
  
  
  def densenet201(**kwargs):
      model = DenseNet(
          num_init_features=64,
          growth_rate=32,
          block_config=(6, 12, 48, 32),
          **kwargs)
      return model
  
  
  def densenet264(**kwargs):
      model = DenseNet(
          num_init_features=64,
          growth_rate=32,
          block_config=(6, 12, 64, 48),
          **kwargs)
      return model
  
  
  def get_fine_tuning_parameters(model, ft_begin_index):
      if ft_begin_index == 0:
          return model.parameters()
  
      ft_module_names = []
      for i in range(ft_begin_index, 5):
          ft_module_names.append('denseblock{}'.format(i))
          ft_module_names.append('transition{}'.format(i))
      ft_module_names.append('norm5')
      ft_module_names.append('classifier')
  
      parameters = []
      for k, v in model.named_parameters():
          for ft_module in ft_module_names:
              if ft_module in k:
                  parameters.append({'params': v})
                  break
          else:
              parameters.append({'params': v, 'lr': 0.0})
  
      return parameters
  
  
  class _DenseLayer(nn.Sequential):
  
      def __init__(self, num_input_features, growth_rate, bn_size, drop_rate):
          super(_DenseLayer, self).__init__()
          self.add_module('norm.1', nn.BatchNorm3d(num_input_features))
          self.add_module('relu.1', nn.ReLU(inplace=True))
          self.add_module('conv.1',
                          nn.Conv3d(
                              num_input_features,
                              bn_size * growth_rate,
                              kernel_size=1,
                              stride=1,
                              bias=False))
          self.add_module('norm.2', nn.BatchNorm3d(bn_size * growth_rate))
          self.add_module('relu.2', nn.ReLU(inplace=True))
          self.add_module('conv.2',
                          nn.Conv3d(
                              bn_size * growth_rate,
                              growth_rate,
                              kernel_size=3,
                              stride=1,
                              padding=1,
                              bias=False))
          self.drop_rate = drop_rate
  
      def forward(self, x):
          new_features = super(_DenseLayer, self).forward(x)
          if self.drop_rate > 0:
              new_features = F.dropout(
                  new_features, p=self.drop_rate, training=self.training)
          return torch.cat([x, new_features], 1)
  
  
  class _DenseBlock(nn.Sequential):
  
      def __init__(self, num_layers, num_input_features, bn_size, growth_rate,
                   drop_rate):
          super(_DenseBlock, self).__init__()
          for i in range(num_layers):
              layer = _DenseLayer(num_input_features + i * growth_rate,
                                  growth_rate, bn_size, drop_rate)
              self.add_module('denselayer%d' % (i + 1), layer)
  
  
  class _Transition(nn.Sequential):
  
      def __init__(self, num_input_features, num_output_features):
          super(_Transition, self).__init__()
          self.add_module('norm', nn.BatchNorm3d(num_input_features))
          self.add_module('relu', nn.ReLU(inplace=True))
          self.add_module('conv',
                          nn.Conv3d(
                              num_input_features,
                              num_output_features,
                              kernel_size=1,
                              stride=1,
                              bias=False))
          self.add_module('pool', nn.AvgPool3d(kernel_size=2, stride=2))
  
  
  class DenseNet(nn.Module):
      """Densenet-BC model class
      Args:
          growth_rate (int) - how many filters to add each layer (k in paper)
          block_config (list of 4 ints) - how many layers in each pooling block
          num_init_features (int) - the number of filters to learn in the first convolution layer
          bn_size (int) - multiplicative factor for number of bottle neck layers
            (i.e. bn_size * k features in the bottleneck layer)
          drop_rate (float) - dropout rate after each dense layer
          num_classes (int) - number of classification classes
      """
  
      def __init__(self,
                   sample_size0,
                   sample_size1,
                   sample_duration,
                   growth_rate=32,
                   block_config=(6, 12, 24, 16),
                   num_init_features=64,
                   bn_size=4,
                   drop_rate=0,
                   num_classes=3,
                   nonlocal_mode='concatenation',
                   attention_dsample=(2, 2, 2)): #change it from 1000 yuankai
  
          super(DenseNet, self).__init__()
  
          self.sample_size0 = sample_size0
          self.sample_size1 = sample_size1
          self.sample_duration = sample_duration
  
          # First convolution
          self.features = nn.Sequential(
              OrderedDict([
                  ('conv0',
                   nn.Conv3d(
                       2,  #yuankai fraom3
                       num_init_features,
                       kernel_size=7,
                       stride=(1, 3, 2),
                       padding=(3, 3, 3),
                       bias=False)),
                  ('norm0', nn.BatchNorm3d(num_init_features)),
                  ('relu0', nn.ReLU(inplace=True)),
                  ('pool0', nn.MaxPool3d(kernel_size=3, stride=2, padding=1)),
              ]))
  
          # Each denseblock
          num_features = num_init_features
          for i, num_layers in enumerate(block_config):
              block = _DenseBlock(
                  num_layers=num_layers,
                  num_input_features=num_features,
                  bn_size=bn_size,
                  growth_rate=growth_rate,
                  drop_rate=drop_rate)
              self.features.add_module('denseblock%d' % (i + 1), block)
              num_features = num_features + num_layers * growth_rate
              if i != len(block_config) - 1:
                  trans = _Transition(
                      num_input_features=num_features,
                      num_output_features=num_features // 2)
                  self.features.add_module('transition%d' % (i + 1), trans)
                  num_features = num_features // 2
  
          # Final batch norm
          self.features.add_module('norm5', nn.BatchNorm2d(num_features))
  
  
          for m in self.modules():
              if isinstance(m, nn.Conv3d):
                  m.weight = nn.init.kaiming_normal(m.weight, mode='fan_out')
              elif isinstance(m, nn.BatchNorm3d) or isinstance(m, nn.BatchNorm2d):
                  m.weight.data.fill_(1)
                  m.bias.data.zero_()
  
          # Linear layer
          self.classifier = nn.Linear(num_features, num_classes)
  
      def forward(self, x):
          features = self.features(x)
          out = F.relu(features, inplace=True)
          last_duration = int(math.ceil(self.sample_duration / 16))
          last_size0 = int(math.floor(self.sample_size0 / 32))
          last_size1 = int(math.floor(self.sample_size1 / 32))
          out = F.avg_pool3d(
              out, kernel_size=(last_duration, last_size0, last_size1)).view(
                  features.size(0), -1)
          out = self.classifier(out)
          return F.log_softmax(out)
  
  
  
  class MultiAttentionBlock(nn.Module):
      def __init__(self, in_size, gate_size, inter_size, nonlocal_mode, sub_sample_factor):
          super(MultiAttentionBlock, self).__init__()
          self.gate_block_1 = GridAttentionBlock3D(in_channels=in_size, gating_channels=gate_size,
                                                   inter_channels=inter_size, mode=nonlocal_mode,
                                                   sub_sample_factor= sub_sample_factor)
          self.combine_gates = nn.Sequential(nn.Conv3d(in_size, in_size, kernel_size=1, stride=1, padding=0),
                                             nn.BatchNorm3d(in_size),
                                             nn.ReLU(inplace=True)
                                             )
  
          # initialise the blocks
          for m in self.children():
              if m.__class__.__name__.find('GridAttentionBlock3D') != -1: continue
              init_weights(m, init_type='kaiming')
  
      def forward(self, input, gating_signal):
          gate_1, attention_1 = self.gate_block_1(input, gating_signal)
  
          return self.combine_gates(gate_1), attention_1