class_docstr: Implementation of a sequential bottleneck adapter block.
code: def __init__(
      self,
      adapter_name,
      input_size,
      down_sample,
      config: BnConfig,
  ):
      super().__init__()
      self.name = adapter_name
      self.input_size = input_size
      self.add_layer_norm_before = config["ln_before"]
      self.add_layer_norm_after = config["ln_after"]
      self.adapter_residual_before_ln = config[
          "adapter_residual_before_ln"
      ]
      self.use_gating = config["use_gating"]
  
      # Params related to input & output of adapter
      self.residual_before_ln = config["residual_before_ln"]
      self.original_ln_before = config["original_ln_before"]
      self.original_ln_after = config["original_ln_after"]
  
      # list for all modules of the adapter, passed into nn.Sequential()
      seq_list = []
  
      # If we want to have a layer norm on input, we add it to seq_list
      if self.add_layer_norm_before:
          self.adapter_norm_before = nn.LayerNorm(self.input_size)
          seq_list.append(self.adapter_norm_before)
  
      # if a downsample size is not passed, we just half the size of the original input
      self.down_sample = down_sample
      if down_sample is None:
          self.down_sample = self.input_size // 2
  
      # ensure that the down sample size is at least 1
      if self.down_sample < 1:
          self.down_sample = 1
  
      if config["phm_layer"]:
          # Linear down projection of the input
          seq_list.append(
              PHMLayer(
                  adapter_name,
                  self.input_size,
                  self.down_sample,
                  "down",
                  config,
              )
          )
      else:
          seq_list.append(nn.Linear(self.input_size, self.down_sample))
  
      # select non-linearity
      self.non_linearity = Activation_Function_Class(
          config["non_linearity"].lower()
      )
  
      seq_list.append(self.non_linearity)
  
      # sequential adapter, first downproject, then non-linearity then upsample. In the forward pass we include the
      # residual connection
      self.adapter_down = nn.Sequential(*seq_list)
  
      # Up projection to input size
      if config["phm_layer"]:
          # Linear down projection of the input
          self.adapter_up = PHMLayer(
              adapter_name,
              self.down_sample,
              self.input_size,
              "up",
              config,
          )
      else:
          self.adapter_up = nn.Linear(self.down_sample, self.input_size)
  
      # Additional scaling factor (from He et al. (2021))
      if isinstance(config["scaling"], float):
          self.scaling = config["scaling"]
      elif config["scaling"] == "learned":
          self.scaling = nn.Parameter(torch.ones(1))
      else:
          raise ValueError(
              "Unknown scaling type: {}".format(config["scaling"])
          )
  
      # If we want to have a layer norm on output, we apply it later after a separate residual connection
      # This means that we learn a new output layer norm, which replaces another layer norm learned in the bert layer
      if self.add_layer_norm_after:
          self.adapter_norm_after = nn.LayerNorm(self.input_size)
  
      if self.use_gating:
          self.gate = nn.Linear(self.input_size, 1)
  
      # if we want to initialize with the bert strategy then this function is called for all the linear layers
      if config["init_weights"] == "bert":
          self.adapter_down.apply(self.init_bert_weights)
          self.adapter_up.apply(self.init_bert_weights)
          if self.use_gating:
              self.gate.apply(self.init_bert_weights)
      elif config["init_weights"] == "mam_adapter":
          with torch.no_grad():
              nn.init.kaiming_uniform_(
                  self.adapter_down[0].weight, a=math.sqrt(5)
              )
              nn.init.zeros_(self.adapter_up.weight)
              nn.init.zeros_(self.adapter_down[0].bias)
              nn.init.zeros_(self.adapter_up.bias)
              if self.use_gating:
                  self.gate.apply(self.init_bert_weights)
      else:
          raise ValueError(
              "Unknown init_weights type: {}".format(
                  config["init_weights"]
              )
          )
  
imports: import math
  import torch
  from torch import nn
  from transformers.activations import get_activation
  from ..configuration import AdapterFusionConfig, BnConfig
  from ..context import ForwardContext
label_desc: Use image node_id 1 to create a new Adapter object from inherited base classes: nn with example: obj = Adapter(adapter_name, input_size, down_sample, config)