class_docstr: Drift detector based on the kernel Maximum Mean Discrepancy (MMD) test.
  
  This is modelled after the MMD drift detection in
  S. Rabanser et al: *Failing Loudly: An Empirical Study of Methods for Detecting Dataset Shift* (NeurIPS), 2019.
  
  Note that our heuristic choice of the kernel bandwith is more closely aligned with that of the original MMD paper and code than S. Rabanser's.
  
  The default kernel is the unnormalized Gaussian (or Squared Exponential) kernel.
docstr: Record a sample as the reference distribution
  
  Args:
      x: The reference data
      n_test: If an int is specified, the last n_test datapoints
          will not be considered part of the reference data. Instead,
          bootstrappin using permutations will be used to determine
          the distribution under the null hypothesis at fit time.
          Future testing must then always be done with n_test elements
          to get p-values.
docstr_tok: ["Record","a","sample","as","the","reference","distribution","Args",":","x",":","The","reference","data","n_test",":","If","an","int","is","specified",",","the","last","n_test","datapoints","will","not","be","considered","part","of","the","reference","data",".","Instead",",","bootstrappin","using","permutations","will","be","used","to","determine","the","distribution","under","the","null","hypothesis","at","fit","time",".","Future","testing","must","then","always","be","done","with","n_test","elements","to","get","p-values","."]
code: def fit(self, x: torch.Tensor, n_test=None):
      """Record a sample as the reference distribution
  
      Args:
          x: The reference data
          n_test: If an int is specified, the last n_test datapoints
              will not be considered part of the reference data. Instead,
              bootstrappin using permutations will be used to determine
              the distribution under the null hypothesis at fit time.
              Future testing must then always be done with n_test elements
              to get p-values."""
      x = x.detach()
      if n_test is None:
          self.base_outputs = x
      else:
          torchdrift.utils.check(
              0 < n_test < x.size(0),
              "n_test must be strictly between 0 and the number of samples",
          )
          self.n_test = n_test
          self.base_outputs = x[:-n_test]
  
          n_ref = x.size(0) - n_test
  
          scores = []
          for i in range(self.n_perm):
              slicing = torch.randperm(x.size(0))
              scores.append(
                  kernel_mmd(
                      x[slicing[:-n_test]],
                      x[slicing[-n_test:]],
                      n_perm=None,
                      kernel=self.kernel,
                  )
              )
          scores = torch.stack(scores)
  
          # limited smallish sample sizes, the MMD appears to exhibit a nonzero offset
          # which vanishes in the limit we adapt. After correcting this, the gamma distribution
          # approximation suggested by Gretton et al seems very good.
          self.dist_min = scores.min().double()
          mean = scores.mean() - self.dist_min
          var = scores.var().double()
          self.dist_alpha = mean**2 / var
          self.dist_beta = mean / var
          self.scores = scores
  
imports: from typing import Optional
  import torch
  from .None import Detector
  import torchdrift.utils
label_desc: Use image node_id 2 for calling the KernelMMDDriftDetector obj's underlying member method code with example usage: obj.fit(x, n_test) without return types