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 forward(self, input_tensor, attention_mask):
      mixed_query_layer = self.query_layer(input_tensor)
      mixed_key_layer = self.key_layer(input_tensor)
      mixed_value_layer = self.value_layer(input_tensor)
  
      queries = self.transpose_for_scores(mixed_query_layer)
      keys = self.transpose_for_scores(mixed_key_layer)
      values = self.transpose_for_scores(mixed_value_layer)
  
      # B, H, L, E = query_layer.shape
      # AutoFormer
      B, L, H, E = queries.shape
      _, S, _, D = values.shape
      if L > S:
          zeros = torch.zeros_like(queries[:, : (L - S), :]).float()
          values = torch.cat([values, zeros], dim=1)
          keys = torch.cat([keys, zeros], dim=1)
      else:
          values = values[:, :L, :, :]
          keys = keys[:, :L, :, :]
  
          # period-based dependencies
      q_fft = torch.fft.rfft(
          queries.permute(0, 2, 3, 1).contiguous(), dim=-1
      )
      k_fft = torch.fft.rfft(
          keys.permute(0, 2, 3, 1).contiguous(), dim=-1
      )
  
      # put into an empty box for sampling
      q_fft_box = torch.zeros(
          B,
          H,
          E,
          len(self.q_index),
          device=q_fft.device,
          dtype=torch.cfloat,
      )
      q_fft_box = q_fft[:, :, :, self.q_index]
  
      k_fft_box = torch.zeros(
          B,
          H,
          E,
          len(self.k_index),
          device=q_fft.device,
          dtype=torch.cfloat,
      )
      k_fft_box = k_fft[:, :, :, self.q_index]
      res = q_fft_box * torch.conj(k_fft_box)
  
      if self.config["use_filter"]:
          # filter
          weight = torch.view_as_complex(self.complex_weight)
          res = res * weight
  
      box_res = torch.zeros(
          B, H, E, L // 2 + 1, device=q_fft.device, dtype=torch.cfloat
      )
      box_res[:, :, :, self.q_index] = res
  
      corr = torch.fft.irfft(box_res, dim=-1)
  
      # time delay agg
      if self.training:
          V = self.time_delay_agg_training(
              values.permute(0, 2, 3, 1).contiguous(), corr
          ).permute(0, 3, 1, 2)
      else:
          V = self.time_delay_agg_inference(
              values.permute(0, 2, 3, 1).contiguous(), corr
          ).permute(0, 3, 1, 2)
  
      new_context_layer_shape = V.size()[:-2] + (self.all_head_size,)
      context_layer = V.view(*new_context_layer_shape)
  
      if self.dual_domain:
          # put into an empty box for sampling
          # q
          q_fft_box = torch.zeros(
              B,
              H,
              E,
              len(self.time_q_index),
              device=q_fft.device,
              dtype=torch.cfloat,
          )
          q_fft_box = q_fft[:, :, :, self.time_q_index]
          spatial_q = torch.zeros(
              B,
              H,
              E,
              L // 2 + 1,
              device=q_fft.device,
              dtype=torch.cfloat,
          )
          spatial_q[:, :, :, self.time_q_index] = q_fft_box
  
          # k
          k_fft_box = torch.zeros(
              B,
              H,
              E,
              len(self.time_k_index),
              device=q_fft.device,
              dtype=torch.cfloat,
          )
          k_fft_box = k_fft[:, :, :, self.time_k_index]
          spatial_k = torch.zeros(
              B,
              H,
              E,
              L // 2 + 1,
              device=k_fft.device,
              dtype=torch.cfloat,
          )
          spatial_k[:, :, :, self.time_k_index] = k_fft_box
  
          # v
          v_fft = torch.fft.rfft(
              values.permute(0, 2, 3, 1).contiguous(), dim=-1
          )
          # put into an empty box for sampling
          v_fft_box = torch.zeros(
              B,
              H,
              E,
              len(self.time_v_index),
              device=v_fft.device,
              dtype=torch.cfloat,
          )
          v_fft_box = v_fft[:, :, :, self.time_v_index]
          spatial_v = torch.zeros(
              B,
              H,
              E,
              L // 2 + 1,
              device=v_fft.device,
              dtype=torch.cfloat,
          )
          spatial_v[:, :, :, self.time_v_index] = v_fft_box
  
          queries = torch.fft.irfft(spatial_q, dim=-1)
          keys = torch.fft.irfft(spatial_k, dim=-1)
          values = torch.fft.irfft(spatial_v, dim=-1)
  
          queries = queries.permute(0, 1, 3, 2)
          keys = keys.permute(0, 1, 3, 2)
          values = values.permute(0, 1, 3, 2)
  
          attention_scores = torch.matmul(
              queries, keys.transpose(-1, -2)
          )
          attention_scores = attention_scores / math.sqrt(
              self.attention_head_size
          )
  
          attention_scores = attention_scores + attention_mask
          attention_probs = nn.Softmax(dim=-1)(attention_scores)
          attention_probs = self.attn_dropout(attention_probs)
          qkv = torch.matmul(attention_probs, values)
          context_layer_spatial = qkv.permute(0, 2, 1, 3).contiguous()
          new_context_layer_shape = context_layer_spatial.size()[
              :-2
          ] + (self.all_head_size,)
          context_layer_spatial = context_layer_spatial.view(
              *new_context_layer_shape
          )
          context_layer = (
              (1 - self.spatial_ratio) * context_layer
              + self.spatial_ratio * context_layer_spatial
          )
  
      hidden_states = self.dense(context_layer)
      hidden_states = self.out_dropout(hidden_states)
      hidden_states = self.LayerNorm(hidden_states + input_tensor)
      return hidden_states
  
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 5 for calling the HybridAttention obj's underlying member method code with example usage: obj.forward(input_tensor, attention_mask) and returns: hidden_states