class_docstr: Multi-Head Attention implementation from https://arxiv.org/abs/1706.03762
  used for Movie+MCAN
class_docstr_tok: ["Multi-Head","Attention","implementation","from","https",":","\/\/arxiv.org\/abs\/1706.03762","used","for","Movie+MCAN"]
code: def qkv_attention(
      self,
      query: torch.Tensor,
      key: torch.Tensor,
      value: torch.Tensor,
      mask: Optional[torch.Tensor] = None,
      dropout: Type[nn.Dropout] = None,
  ) -> Tuple[torch.Tensor, torch.Tensor]:
      d_k = query.size(-1)
      scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(
          d_k
      )
      if mask is not None:
          scores.data.masked_fill_(mask.unsqueeze(1).unsqueeze(2), -1e9)
  
      p_attn = nn.functional.softmax(scores, dim=-1)
      if dropout is not None:
          p_attn = dropout(p_attn)
  
      return torch.matmul(p_attn, value), p_attn
  
imports: import math
  from typing import Optional, Tuple, Type
  import torch
  from mmf.modules.layers import GatedTanh, ModalCombineLayer, TransformLayer
  from torch import nn
label_desc: Use image node_id 2 for calling the MovieMcanMultiHeadAttention obj's underlying member method code with example usage: obj.qkv_attention(query, key, value, mask, dropout) and returns: torch,  p_attn