class_docstr: Hybrid Attention layer: combine time domain self-attention layer and frequency domain attention layer.
  
  Args:
      input_tensor (torch.Tensor): the input of the multi-head Hybrid Attention layer
      attention_mask (torch.Tensor): the attention mask for input tensor
  
  Returns:
      hidden_states (torch.Tensor): the output of the multi-head Hybrid Attention layer
class_docstr_tok: ["Hybrid","Attention","layer",":","combine","time","domain","self-attention","layer","and","frequency","domain","attention","layer",".","Args",":","input_tensor","(","torch.Tensor",")",":","the","input","of","the","multi-head","Hybrid","Attention","layer","attention_mask","(","torch.Tensor",")",":","the","attention","mask","for","input","tensor","Returns",":","hidden_states","(","torch.Tensor",")",":","the","output","of","the","multi-head","Hybrid","Attention","layer"]
code: def __init__(
      self,
      n_heads,
      hidden_size,
      hidden_dropout_prob,
      attn_dropout_prob,
      layer_norm_eps,
      i,
      config,
  ):
      super(HybridAttention, self).__init__()
      if hidden_size % n_heads != 0:
          raise ValueError(
              "The hidden size (%d) is not a multiple of the number of attention "
              "heads (%d)" % (hidden_size, n_heads)
          )
  
      self.factor = config["topk_factor"]
      self.scale = None
      self.mask_flag = True
      self.output_attention = False
      self.dropout = nn.Dropout(0.1)
      self.config = config
      self.num_attention_heads = n_heads
      self.attention_head_size = int(hidden_size / n_heads)
      self.all_head_size = (
          self.num_attention_heads * self.attention_head_size
      )
      self.query_layer = nn.Linear(hidden_size, self.all_head_size)
      self.key_layer = nn.Linear(hidden_size, self.all_head_size)
      self.value_layer = nn.Linear(hidden_size, self.all_head_size)
      self.attn_dropout = nn.Dropout(attn_dropout_prob)
      self.dense = nn.Linear(hidden_size, hidden_size)
      self.LayerNorm = nn.LayerNorm(hidden_size, eps=layer_norm_eps)
      self.out_dropout = nn.Dropout(hidden_dropout_prob)
      self.filter_mixer = None
      self.global_ratio = config["global_ratio"]
      self.n_layers = config["n_layers"]
      if self.global_ratio > (1 / self.n_layers):
          print(
              "{}>{}:{}".format(
                  self.global_ratio,
                  1 / self.n_layers,
                  self.global_ratio > (1 / self.n_layers),
              )
          )
          self.filter_mixer = "G"
      else:
          print(
              "{}>{}:{}".format(
                  self.global_ratio,
                  1 / self.n_layers,
                  self.global_ratio > (1 / self.n_layers),
              )
          )
          self.filter_mixer = "L"
      self.max_item_list_length = config["MAX_ITEM_LIST_LENGTH"]
      self.dual_domain = config["dual_domain"]
      self.slide_step = (
          (self.max_item_list_length // 2 + 1) * (1 - self.global_ratio)
      ) // (self.n_layers - 1)
      self.local_ratio = 1 / self.n_layers
      self.filter_size = self.local_ratio * (
          self.max_item_list_length // 2 + 1
      )
  
      if self.filter_mixer == "G":
          self.w = self.global_ratio
          self.s = self.slide_step
  
      if self.filter_mixer == "L":
          self.w = self.local_ratio
          self.s = self.filter_size
  
      self.left = int(
          ((self.max_item_list_length // 2 + 1) * (1 - self.w))
          - (i * self.s)
      )
      self.right = int(
          (self.max_item_list_length // 2 + 1) - i * self.s
      )
  
      self.q_index = list(range(self.left, self.right))
      self.k_index = list(range(self.left, self.right))
      self.v_index = list(range(self.left, self.right))
      # if sample in time domain
      self.std = config["std"]
      if self.std:
          self.time_q_index = self.q_index
          self.time_k_index = self.k_index
          self.time_v_index = self.v_index
      else:
          self.time_q_index = list(
              range(self.max_item_list_length // 2 + 1)
          )
          self.time_k_index = list(
              range(self.max_item_list_length // 2 + 1)
          )
          self.time_v_index = list(
              range(self.max_item_list_length // 2 + 1)
          )
  
      print(
          "modes_q={}, index_q={}".format(
              len(self.q_index), self.q_index
          )
      )
      print(
          "modes_k={}, index_k={}".format(
              len(self.k_index), self.k_index
          )
      )
      print(
          "modes_v={}, index_v={}".format(
              len(self.v_index), self.v_index
          )
      )
  
      if self.config["dual_domain"]:
          self.spatial_ratio = self.config["spatial_ratio"]
  
imports: import random
  import numpy
  import torch
  from torch import nn
  import torch.nn.functional
  import math
  import torch.nn.functional
  from recbole.model.abstract_recommender import SequentialRecommender
  from recbole.model.loss import BPRLoss
  from recbole.data.interaction import Interaction
label_desc: Use image node_id 1 to create a new HybridAttention object from inherited base classes: nn with example: obj = HybridAttention(n_heads, hidden_size, hidden_dropout_prob, attn_dropout_prob, layer_norm_eps, i, config)