class_docstr: Quantization bottleneck.
  
  This class quantizes its input based on a codebook. Each entry is quantized
  to its nearest codebook representation according to Euclidean distance.
  
  Args:
      codebook_sizes: Size of the codebook for each quantization level.
      hidden_dims: Hidden dimension size, i.e., the sizes of the input
          vectors.
      init_distribution: Initialization distribution for the codebooks.
      normalize_codebook: Whether to renormalize the codebook prior to each
          quantization run.
code: def update_metrics(self):
      assert (
          len(self.percentage_hits)
          == len(self.max_hits)
          == len(self.perplexities)
      )
      num_codebooks = len(self.percentage_hits)
      # codebook hit stats
      for level in range(num_codebooks):
          codebook_hits: Tensor = getattr(
              self, f"codebook_hits_{level}"
          )
          self.percentage_hits[level] = (
              torch.sum(codebook_hits != 0) / codebook_hits.numel()
          )
          self.max_hits[level] = torch.max(codebook_hits)
          probs = codebook_hits / torch.sum(codebook_hits)
          self.perplexities[level] = 2 ** (
              -torch.sum(probs * torch.log2(probs + 1e-7))
          )
  
file_path: NeuralCompression/neuralcompression/layers/_q_bottleneck.py
imports: from typing import NamedTuple, Optional, Sequence
  import torch
  import torch.nn
  import torch.nn.functional
  from torch import Tensor
label_desc: Use image node_id 3 for calling the QBottleneck obj's underlying member method code with example usage: obj.update_metrics() without return types