class_docstr: This class is adapted from the compacter implementation at https://github.com/rabeehk/compacter
code: def __init__(
      self,
      adapter_name: str,
      in_features: int,
      out_features: int,
      position: str,
      config: dict,
  ) -> None:
      super(PHMLayer, self).__init__()
      assert config["hypercomplex_nonlinearity"] in [
          "phm",
          "glorot-normal",
          "glorot-uniform",
          "normal",
      ]
      assert config["phm_c_init"] in ["normal", "uniform"]
      assert (
          in_features % config["phm_dim"] == 0
      ), f"Argument `in_features`={in_features} is not divisble be `phm_dim`{config['phm_dim']}"
      assert (
          out_features % config["phm_dim"] == 0
      ), f"Argument `out_features`={out_features} is not divisble be `phm_dim`{config['phm_dim']}"
      self.config = config
      self.name = adapter_name
      self.in_features = in_features
      self.out_features = out_features
      self.position = position
      self.learn_phm = config["learn_phm"]
      self.phm_dim = config["phm_dim"]
      self._in_feats_per_axis = in_features // config["phm_dim"]
      self._out_feats_per_axis = out_features // config["phm_dim"]
      self.phm_rank = config["phm_rank"]
      self.phm_init_range = config["phm_init_range"]
      self.shared_phm_rule = config["shared_phm_rule"]
      self.factorized_phm_rule = config["factorized_phm_rule"]
      if not self.shared_phm_rule:
          if self.factorized_phm_rule:
              self.phm_rule_left = nn.Parameter(
                  torch.FloatTensor(self.phm_dim, self.phm_dim, 1),
                  requires_grad=self.learn_phm,
              )
              self.phm_rule_right = nn.Parameter(
                  torch.FloatTensor(self.phm_dim, 1, self.phm_dim),
                  requires_grad=self.learn_phm,
              )
          else:
              self.phm_rule = nn.Parameter(
                  torch.FloatTensor(
                      self.phm_dim, self.phm_dim, self.phm_dim
                  ),
                  requires_grad=self.learn_phm,
              )
      self.bias_flag = config["phm_bias"]
      self.w_init = config["hypercomplex_nonlinearity"]
      self.c_init = config["phm_c_init"]
      self.shared_W_phm = config["shared_W_phm"]
      self.factorized_phm_W = config["factorized_phm_W"]
      if not self.shared_W_phm:
          if self.factorized_phm_W:
              self.W_left = nn.Parameter(
                  torch.Tensor(
                      size=(
                          self.phm_dim,
                          self._in_feats_per_axis,
                          self.phm_rank,
                      )
                  ),
                  requires_grad=True,
              )
              self.W_right = nn.Parameter(
                  torch.Tensor(
                      size=(
                          self.phm_dim,
                          self.phm_rank,
                          self._out_feats_per_axis,
                      )
                  ),
                  requires_grad=True,
              )
          else:
              self.W = nn.Parameter(
                  torch.Tensor(
                      size=(
                          self.phm_dim,
                          self._in_feats_per_axis,
                          self._out_feats_per_axis,
                      )
                  ),
                  requires_grad=True,
              )
      if self.bias_flag:
          self.b = nn.Parameter(torch.Tensor(out_features))
      else:
          self.register_parameter("b", None)
      self.reset_parameters()
  
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 PHMLayer object from inherited base classes: nn with example: obj = PHMLayer(adapter_name, in_features, out_features, position, config)