docstr: 一般输入信息 X 时，假设 K = V = X
  
  att_weight = softmax( score_func(q, k) )
  att = sum( att_weight * v )
  
  :param Q: [..., L, H]
  :param K: [..., S, H]
  :param V: [..., S, H]
  :param mask_out: [..., 1, S]
  :return:
code: def forward(self, Q, K, V, mask_out=None, head_mask=None):
      """
      一般输入信息 X 时，假设 K = V = X
  
      att_weight = softmax( score_func(q, k) )
      att = sum( att_weight * v )
  
      :param Q: [..., L, H]
      :param K: [..., S, H]
      :param V: [..., S, H]
      :param mask_out: [..., 1, S]
      :return:
      """
      H = Q.size(-1)
  
      scale = float(H) ** 0.5
      attention_weight = torch.matmul(Q, K.transpose(-1, -2)) / scale
  
      if mask_out is not None:
          # 当 DotAttention 单独使用时（几乎不会），保证维度一样
          while mask_out.dim() != Q.dim():
              mask_out = mask_out.unsqueeze(1)
          attention_weight.masked_fill_(mask_out, -1e8)
  
      attention_weight = F.softmax(attention_weight, dim=-1)
  
      attention_weight = F.dropout(attention_weight, self.dropout)
  
      # mask heads if we want to:
      # multi head 才会使用
      if head_mask is not None:
          attention_weight = attention_weight * head_mask
  
      attention_out = torch.matmul(attention_weight, V)
  
      return attention_out, attention_weight
  
file_path: DeepKE/src/deepke/attribution_extraction/standard/module/Attention.py
imports: import logging
  import torch
  import torch.nn
  import torch.nn.functional
label_desc: Use image node_id 2 for calling the DotAttention obj's underlying member method code with example usage: obj.forward(Q, K, V, mask_out, head_mask) and returns: attention_out,  attention_weight