docstr: Implements the DkNN algorithm. See https://arxiv.org/abs/1803.04765 for more details.
  
  :param neighbors: number of neighbors to find per layer.
  :param layers: a list of layer names to include in the DkNN.
  :param get_activations: a callable that takes a np array and a layer name and returns its activations on the data.
  :param train_data: a np array of training data.
  :param train_labels: a np vector of training labels.
  :param nb_classes: the number of classes in the task.
  :param scope: a TF scope that was used to create the underlying model.
  :param nb_tables: number of tables used by FALCONN to perform locality-sensitive hashing.
  :param number_bits: number of hash bits used by LSH.
code: def __init__(
      self,
      neighbors,
      layers,
      get_activations,
      train_data,
      train_labels,
      nb_classes,
      scope=None,
      nb_tables=200,
      number_bits=17,
  ):
      """
      Implements the DkNN algorithm. See https://arxiv.org/abs/1803.04765 for more details.
  
      :param neighbors: number of neighbors to find per layer.
      :param layers: a list of layer names to include in the DkNN.
      :param get_activations: a callable that takes a np array and a layer name and returns its activations on the data.
      :param train_data: a np array of training data.
      :param train_labels: a np vector of training labels.
      :param nb_classes: the number of classes in the task.
      :param scope: a TF scope that was used to create the underlying model.
      :param nb_tables: number of tables used by FALCONN to perform locality-sensitive hashing.
      :param number_bits: number of hash bits used by LSH.
      """
      super(DkNNModel, self).__init__(
          nb_classes=nb_classes, scope=scope
      )
      self.neighbors = neighbors
      self.nb_tables = nb_tables
      self.layers = layers
      self.get_activations = get_activations
      self.nb_cali = -1
      self.calibrated = False
      self.number_bits = number_bits
  
      # Compute training data activations
      self.nb_train = train_labels.shape[0]
      assert self.nb_train == train_data.shape[0]
      self.train_activations = get_activations(train_data)
      self.train_labels = train_labels
  
      # Build locality-sensitive hashing tables for training representations
      self.train_activations_lsh = copy.copy(self.train_activations)
      self.init_lsh()
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from __future__ import unicode_literals
  import copy
  import os
  from bisect import bisect_left
  import matplotlib
  import matplotlib.pyplot
  import numpy
  from six.moves import xrange
  import enum
  import tensorflow
  from cleverhans.attacks import FastGradientMethod
  from cleverhans.loss import CrossEntropy
  from cleverhans.dataset import MNIST
  from cleverhans.model import Model
  from cleverhans.picklable_model import MLP, Conv2D, ReLU, Flatten, Linear, Softmax
  from cleverhans.train import train
  from cleverhans.utils_tf import batch_eval, model_eval
label_desc: Use image node_id 1 to create a new DkNNModel object from inherited base classes: Model with example: obj = DkNNModel(neighbors, layers, get_activations, train_data, train_labels, nb_classes, scope, nb_tables, number_bits)