class_docstr: input:
      query --- [N, T_q, query_dim]
      key --- [N, T_k, key_dim]
  output:
      out --- [N, T_q, num_units]
code: def __init__(
      self, query_dim: int, key_dim: int, num_units: int, num_heads: int
  ):
      super().__init__()
      self.num_units = num_units
      self.num_heads = num_heads
      self.key_dim = key_dim
  
      self.W_query = nn.Linear(
          in_features=query_dim, out_features=num_units, bias=False
      )
      self.W_key = nn.Linear(
          in_features=key_dim, out_features=num_units, bias=False
      )
      self.W_value = nn.Linear(
          in_features=key_dim, out_features=num_units, bias=False
      )
  
imports: import math
  from typing import Tuple
  import torch
  import torch.nn
  import torch.nn.functional
  from TTS.tts.layers.delightful_tts.conv_layers import Conv1dGLU, DepthWiseConv1d, PointwiseConv1d
  from TTS.tts.layers.delightful_tts.networks import GLUActivation
label_desc: Use image node_id 1 to create a new MultiHeadAttention object from inherited base classes: nn with example: obj = MultiHeadAttention(query_dim, key_dim, num_units, num_heads)