class_docstr: Bidirectional fusion Multi-Head Attention layer.
  
  Args:
      v_dim (int): The dimension of the vision input.
      l_dim (int): The dimension of the language input.
      embed_dim (int): The embedding dimension for the attention operation.
      num_heads (int): The number of attention heads.
      dropout (float, optional): The dropout probability. Defaults to 0.1.
class_docstr_tok: ["Bidirectional","fusion","Multi-Head","Attention","layer",".","Args",":","v_dim","(","int",")",":","The","dimension","of","the","vision","input",".","l_dim","(","int",")",":","The","dimension","of","the","language","input",".","embed_dim","(","int",")",":","The","embedding","dimension","for","the","attention","operation",".","num_heads","(","int",")",":","The","number","of","attention","heads",".","dropout","(","float",",","optional",")",":","The","dropout","probability",".","Defaults","to","0.1","."]
code: def forward(
      self,
      vision: Tensor,
      lang: Tensor,
      attention_mask_v: Optional[Tensor] = None,
      attention_mask_l: Optional[Tensor] = None,
  ) -> Tuple[Tensor, Tensor]:
      bsz, tgt_len, _ = vision.size()
  
      query_states = self.v_proj(vision) * self.scale
      key_states = self._shape(self.l_proj(lang), -1, bsz)
      value_v_states = self._shape(self.values_v_proj(vision), -1, bsz)
      value_l_states = self._shape(self.values_l_proj(lang), -1, bsz)
  
      proj_shape = (bsz * self.num_heads, -1, self.head_dim)
      query_states = self._shape(query_states, tgt_len, bsz).view(
          *proj_shape
      )
      key_states = key_states.view(*proj_shape)
      value_v_states = value_v_states.view(*proj_shape)
      value_l_states = value_l_states.view(*proj_shape)
  
      src_len = key_states.size(1)
      attn_weights = torch.bmm(query_states, key_states.transpose(1, 2))
  
      if attn_weights.size() != (
          bsz * self.num_heads,
          tgt_len,
          src_len,
      ):
          raise ValueError(
              f"Attention weights should be of "
              f"size {(bsz * self.num_heads, tgt_len, src_len)}, "
              f"but is {attn_weights.size()}"
          )
  
      if self.stable_softmax_2d:
          attn_weights = attn_weights - attn_weights.max()
  
      if self.clamp_min_for_underflow:
          # Do not increase -50000, data type half has quite limited range
          attn_weights = torch.clamp(attn_weights, min=-MAX_CLAMP_VALUE)
      if self.clamp_max_for_overflow:
          # Do not increase 50000, data type half has quite limited range
          attn_weights = torch.clamp(attn_weights, max=MAX_CLAMP_VALUE)
  
      attn_weights_T = attn_weights.transpose(1, 2)
      attn_weights_l = (
          attn_weights_T
          - torch.max(attn_weights_T, dim=-1, keepdim=True)[0]
      )
      if self.clamp_min_for_underflow:
          # Do not increase -50000, data type half has quite limited range
          attn_weights_l = torch.clamp(
              attn_weights_l, min=-MAX_CLAMP_VALUE
          )
      if self.clamp_max_for_overflow:
          # Do not increase 50000, data type half has quite limited range
          attn_weights_l = torch.clamp(
              attn_weights_l, max=MAX_CLAMP_VALUE
          )
  
      if attention_mask_v is not None:
          attention_mask_v = (
              attention_mask_v[:, None, None, :]
              .repeat(1, self.num_heads, 1, 1)
              .flatten(0, 1)
          )
          attn_weights_l.masked_fill_(attention_mask_v, float("-inf"))
  
      attn_weights_l = attn_weights_l.softmax(dim=-1)
  
      if attention_mask_l is not None:
          assert attention_mask_l.dim() == 2
          attention_mask = attention_mask_l.unsqueeze(1).unsqueeze(1)
          attention_mask = attention_mask.expand(
              bsz, 1, tgt_len, src_len
          )
          attention_mask = attention_mask.masked_fill(
              attention_mask == 0, -9e15
          )
  
          if attention_mask.size() != (bsz, 1, tgt_len, src_len):
              raise ValueError(
                  "Attention mask should be of "
                  f"size {(bsz, 1, tgt_len, src_len)}"
              )
          attn_weights = (
              attn_weights.view(bsz, self.num_heads, tgt_len, src_len)
              + attention_mask
          )
          attn_weights = attn_weights.view(
              bsz * self.num_heads, tgt_len, src_len
          )
  
      attn_weights_v = nn.functional.softmax(attn_weights, dim=-1)
  
      attn_probs_v = F.dropout(
          attn_weights_v, p=self.dropout, training=self.training
      )
      attn_probs_l = F.dropout(
          attn_weights_l, p=self.dropout, training=self.training
      )
  
      attn_output_v = torch.bmm(attn_probs_v, value_l_states)
      attn_output_l = torch.bmm(attn_probs_l, value_v_states)
  
      if attn_output_v.size() != (
          bsz * self.num_heads,
          tgt_len,
          self.head_dim,
      ):
          raise ValueError(
              "`attn_output_v` should be of "
              f"size {(bsz, self.num_heads, tgt_len, self.head_dim)}, "
              f"but is {attn_output_v.size()}"
          )
  
      if attn_output_l.size() != (
          bsz * self.num_heads,
          src_len,
          self.head_dim,
      ):
          raise ValueError(
              "`attn_output_l` should be of size "
              f"{(bsz, self.num_heads, src_len, self.head_dim)}, "
              f"but is {attn_output_l.size()}"
          )
  
      attn_output_v = attn_output_v.view(
          bsz, self.num_heads, tgt_len, self.head_dim
      )
      attn_output_v = attn_output_v.transpose(1, 2)
      attn_output_v = attn_output_v.reshape(
          bsz, tgt_len, self.embed_dim
      )
  
      attn_output_l = attn_output_l.view(
          bsz, self.num_heads, src_len, self.head_dim
      )
      attn_output_l = attn_output_l.transpose(1, 2)
      attn_output_l = attn_output_l.reshape(
          bsz, src_len, self.embed_dim
      )
  
      attn_output_v = self.out_v_proj(attn_output_v)
      attn_output_l = self.out_l_proj(attn_output_l)
  
      return attn_output_v, attn_output_l
  
imports: import math
  from typing import Dict, Optional, Tuple
  import torch
  import torch.nn
  import torch.nn.functional
  import torch.utils.checkpoint
  from mmcv.cnn.bricks import DropPath
  from torch import Tensor
label_desc: Use image node_id 4 for calling the BiMultiHeadAttention obj's underlying member method code with example usage: obj.forward(vision, lang, attention_mask_v, attention_mask_l) and returns: attn_output_v,  attn_output_l