class_docstr: Emformer layer attention module.
  
  Args:
      input_dim (int): input dimension.
      num_heads (int): number of attention heads in each Emformer layer.
      dropout (float, optional): dropout probability. (Default: 0.0)
      weight_init_gain (float or None, optional): scale factor to apply when initializing
          attention module parameters. (Default: ``None``)
      tanh_on_mem (bool, optional): if ``True``, applies tanh to memory elements. (Default: ``False``)
      negative_inf (float, optional): value to use for negative infinity in attention weights. (Default: -1e8)
class_docstr_tok: ["Emformer","layer","attention","module",".","Args",":","input_dim","(","int",")",":","input","dimension",".","num_heads","(","int",")",":","number","of","attention","heads","in","each","Emformer","layer",".","dropout","(","float",",","optional",")",":","dropout","probability",".","(","Default",":","0.0",")","weight_init_gain","(","float","or","None",",","optional",")",":","scale","factor","to","apply","when","initializing","attention","module","parameters",".","(","Default",":","``","None","``",")","tanh_on_mem","(","bool",",","optional",")",":","if","``","True","``",",","applies","tanh","to","memory","elements",".","(","Default",":","``","False","``",")","negative_inf","(","float",",","optional",")",":","value","to","use","for","negative","infinity","in","attention","weights",".","(","Default",":","-1e8",")"]
code: def _forward_impl(
      self,
      utterance: torch.Tensor,
      lengths: torch.Tensor,
      right_context: torch.Tensor,
      summary: torch.Tensor,
      mems: torch.Tensor,
      attention_mask: torch.Tensor,
      left_context_key: Optional[torch.Tensor] = None,
      left_context_val: Optional[torch.Tensor] = None,
  ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
      B = utterance.size(1)
      T = right_context.size(0) + utterance.size(0) + summary.size(0)
  
      # Compute query with [right context, utterance, summary].
      query = self.emb_to_query(
          torch.cat([right_context, utterance, summary])
      )
  
      # Compute key and value with [mems, right context, utterance].
      key, value = self.emb_to_key_value(
          torch.cat([mems, right_context, utterance])
      ).chunk(chunks=2, dim=2)
  
      if left_context_key is not None and left_context_val is not None:
          right_context_blocks_length = (
              T - torch.max(lengths).int() - summary.size(0)
          )
          key = torch.cat(
              [
                  key[: mems.size(0) + right_context_blocks_length],
                  left_context_key,
                  key[mems.size(0) + right_context_blocks_length :],
              ],
          )
          value = torch.cat(
              [
                  value[: mems.size(0) + right_context_blocks_length],
                  left_context_val,
                  value[mems.size(0) + right_context_blocks_length :],
              ],
          )
  
      # Compute attention weights from query, key, and value.
      reshaped_query, reshaped_key, reshaped_value = [
          tensor.contiguous()
          .view(
              -1, B * self.num_heads, self.input_dim // self.num_heads
          )
          .transpose(0, 1)
          for tensor in [query, key, value]
      ]
      attention_weights = torch.bmm(
          reshaped_query * self.scaling, reshaped_key.transpose(1, 2)
      )
  
      # Compute padding mask.
      padding_mask = _gen_padding_mask(
          utterance,
          right_context,
          summary,
          lengths,
          mems,
          left_context_key,
      )
  
      # Compute attention probabilities.
      attention_probs = self._gen_attention_probs(
          attention_weights, attention_mask, padding_mask
      )
  
      # Compute attention.
      attention = torch.bmm(attention_probs, reshaped_value)
      if attention.shape != (
          B * self.num_heads,
          T,
          self.input_dim // self.num_heads,
      ):
          raise AssertionError(
              "Computed attention has incorrect dimensions"
          )
      attention = (
          attention.transpose(0, 1)
          .contiguous()
          .view(T, B, self.input_dim)
      )
  
      # Apply output projection.
      output_right_context_mems = self.out_proj(attention)
  
      summary_length = summary.size(0)
      output_right_context = output_right_context_mems[
          : T - summary_length
      ]
      output_mems = output_right_context_mems[T - summary_length :]
      if self.tanh_on_mem:
          output_mems = torch.tanh(output_mems)
      else:
          output_mems = torch.clamp(output_mems, min=-10, max=10)
  
      return output_right_context, output_mems, key, value
  
imports: import math
  from typing import List, Optional, Tuple
  import torch
label_desc: Use image node_id 4 for calling the _EmformerAttention obj's underlying member method code with example usage: obj._forward_impl(utterance, lengths, right_context, summary, mems, attention_mask, left_context_key, left_context_val) and returns: output_right_context,  output_mems,  key,  value