class_docstr: NetVLAD module
  Args:
      cluster_size (int): cluster size
      feature_size (int): feature size
      ghost_clusters (int): ghost cluster size
      add_batch_norm (bool): add batch normalization
docstr: Aggregates feature maps into a fixed size representation.  In the following
  notation, B = batch_size, N = num_features, K = num_clusters, D = feature_size.
  
  Args:
      x (th.Tensor): B x N x D
  
  Returns:
      (th.Tensor): B x DK
docstr_tok: ["Aggregates","feature","maps","into","a","fixed","size","representation",".","In","the","following","notation",",","B","=","batch_size",",","N","=","num_features",",","K","=","num_clusters",",","D","=","feature_size",".","Args",":","x","(","th.Tensor",")",":","B","x","N","x","D","Returns",":","(","th.Tensor",")",":","B","x","DK"]
code: def forward(self, x, mask=None):
      """Aggregates feature maps into a fixed size representation.  In the following
      notation, B = batch_size, N = num_features, K = num_clusters, D = feature_size.
  
      Args:
          x (th.Tensor): B x N x D
  
      Returns:
          (th.Tensor): B x DK
      """
      _ = mask
      # self.sanity_checks(x)
      max_sample = x.size()[1]
      x = x.view(-1, self.feature_size)  # B x N x D -> BN x D
  
      if x.device != self.clusters.device:
          msg = f"x.device {x.device} != cluster.device {self.clusters.device}"
          raise ValueError(msg)
  
      assignment = th.matmul(
          x, self.clusters
      )  # (BN x D) x (D x (K+G)) -> BN x (K+G)
  
      if self.batch_norm:
          assignment = self.batch_norm(assignment)
  
      assignment = F.softmax(
          assignment, dim=1
      )  # BN x (K+G) -> BN x (K+G)
      # remove ghost assigments
      assignment = assignment[:, : self.cluster_size]
      assignment = assignment.view(
          -1, max_sample, self.cluster_size
      )  # -> B x N x K
      a_sum = th.sum(
          assignment, dim=1, keepdim=True
      )  # B x N x K -> B x 1 x K
      a = a_sum * self.clusters2
  
      assignment = assignment.transpose(1, 2)  # B x N x K -> B x K x N
  
      x = x.view(
          -1, max_sample, self.feature_size
      )  # BN x D -> B x N x D
      vlad = th.matmul(
          assignment, x
      )  # (B x K x N) x (B x N x D) -> B x K x D
      vlad = vlad.transpose(1, 2)  # -> B x D x K
      vlad = vlad - a
  
      # L2 intra norm
      vlad = F.normalize(vlad)
  
      # flattening + L2 norm
      vlad = vlad.reshape(
          -1, self.cluster_size * self.feature_size
      )  # -> B x DK
      vlad = F.normalize(vlad)
      return vlad
  
imports: import math
  import torch.nn.functional
  import torch
  from torch import nn
label_desc: Use image node_id 2 for calling the NetVLAD obj's underlying member method code with example usage: obj.forward(x, mask) and returns: vlad