class_docstr: Multi-head self attention implement.
  
  Args:
      multiheads (int): The number of heads.
      head_dim (object): Dimention of each head.
      mask_right (boolean): whether to mask right words.
  
  Returns:
      object: Weighted sum after attention.
docstr: Core logic of multi-head self attention.
  
  Args:
      QKVs (list): inputs of multi-head self attention i.e. query, key and value.
  
  Returns:
      object: ouput tensors.
docstr_tok: ["Core","logic","of","multi-head","self","attention",".","Args",":","QKVs","(","list",")",":","inputs","of","multi-head","self","attention","i.e",".","query",",","key","and","value",".","Returns",":","object",":","ouput","tensors","."]
code: def call(self, QKVs):
      """Core logic of multi-head self attention.
  
      Args:
          QKVs (list): inputs of multi-head self attention i.e. query, key and value.
  
      Returns:
          object: ouput tensors.
      """
      if len(QKVs) == 3:
          Q_seq, K_seq, V_seq = QKVs
          Q_len, V_len = None, None
      elif len(QKVs) == 5:
          Q_seq, K_seq, V_seq, Q_len, V_len = QKVs
      Q_seq = K.dot(Q_seq, self.WQ)
      Q_seq = K.reshape(
          Q_seq,
          shape=(-1, K.shape(Q_seq)[1], self.multiheads, self.head_dim),
      )
      Q_seq = K.permute_dimensions(Q_seq, pattern=(0, 2, 1, 3))
  
      K_seq = K.dot(K_seq, self.WK)
      K_seq = K.reshape(
          K_seq,
          shape=(-1, K.shape(K_seq)[1], self.multiheads, self.head_dim),
      )
      K_seq = K.permute_dimensions(K_seq, pattern=(0, 2, 1, 3))
  
      V_seq = K.dot(V_seq, self.WV)
      V_seq = K.reshape(
          V_seq,
          shape=(-1, K.shape(V_seq)[1], self.multiheads, self.head_dim),
      )
      V_seq = K.permute_dimensions(V_seq, pattern=(0, 2, 1, 3))
  
      A = einsum("abij, abkj -> abik", Q_seq, K_seq) / K.sqrt(
          K.cast(self.head_dim, dtype="float32")
      )
      A = K.permute_dimensions(
          A, pattern=(0, 3, 2, 1)
      )  # A.shape=[batch_size,K_sequence_length,Q_sequence_length,self.multiheads]
  
      A = self.Mask(A, V_len, "add")
      A = K.permute_dimensions(A, pattern=(0, 3, 2, 1))
  
      if self.mask_right:
          ones = K.ones_like(A[:1, :1])
          lower_triangular = K.tf.matrix_band_part(
              ones, num_lower=-1, num_upper=0
          )
          mask = (ones - lower_triangular) * 1e12
          A = A - mask
      A = K.softmax(A)
  
      O_seq = einsum("abij, abjk -> abik", A, V_seq)
      O_seq = K.permute_dimensions(O_seq, pattern=(0, 2, 1, 3))
  
      O_seq = K.reshape(
          O_seq, shape=(-1, K.shape(O_seq)[1], self.output_dim)
      )
      O_seq = self.Mask(O_seq, Q_len, "mul")
      return O_seq
  
imports: import tensorflow.compat.v1.keras
  from tensorflow.compat.v1.linalg import einsum
  from tensorflow.compat.v1.keras import layers
  from tensorflow.compat.v1.keras import backend
label_desc: Use image node_id 5 for calling the SelfAttention obj's underlying member method code with example usage: obj.call(QKVs) and returns: O_seq