class_docstr: Wrap another tf optimizer with BoltOn privacy protocol.
  
  BoltOn optimizer wraps another tf optimizer to be used
  as the visible optimizer to the tf model. No matter the optimizer
  passed, "BoltOn" enables the bolt-on model to control the learning rate
  based on the strongly convex loss.
  
  To use the BoltOn method, you must:
  1. instantiate it with an instantiated tf optimizer and StrongConvexLoss.
  2. use it as a context manager around your .fit method internals.
  
  This can be accomplished by the following:
  optimizer = tf.optimizers.SGD()
  loss = privacy.bolt_on.losses.StrongConvexBinaryCrossentropy()
  bolton = BoltOn(optimizer, loss)
  with bolton(*args) as _:
    model.fit()
  The args required for the context manager can be found in the __call__
  method.
  
  For more details on the strong convexity requirements, see:
  Bolt-on Differential Privacy for Scalable Stochastic Gradient
  Descent-based Analytics by Xi Wu et. al.
docstr: Accepts required values for bolton method from context entry point.
  
  Stores them on the optimizer for use throughout fitting.
  
  Args:
    noise_distribution: the noise distribution to pick. see
      _accepted_distributions and get_noise for possible values.
    epsilon: privacy parameter. Lower gives more privacy but less utility.
    layers: list of Keras/Tensorflow layers. Can be found as model.layers
    class_weights: class_weights used, which may either be a scalar or 1D
      tensor with dim == n_classes.
    n_samples: number of rows/individual samples in the training set
    batch_size: batch size used.
  
  Returns:
    self, to be used by the __enter__ method for context.
docstr_tok: ["Accepts","required","values","for","bolton","method","from","context","entry","point",".","Stores","them","on","the","optimizer","for","use","throughout","fitting",".","Args",":","noise_distribution",":","the","noise","distribution","to","pick",".","see","_accepted_distributions","and","get_noise","for","possible","values",".","epsilon",":","privacy","parameter",".","Lower","gives","more","privacy","but","less","utility",".","layers",":","list","of","Keras\/Tensorflow","layers",".","Can","be","found","as","model.layers","class_weights",":","class_weights","used",",","which","may","either","be","a","scalar","or","1D","tensor","with","dim","==","n_classes",".","n_samples",":","number","of","rows\/individual","samples","in","the","training","set","batch_size",":","batch","size","used",".","Returns",":","self",",","to","be","used","by","the","__enter__","method","for","context","."]
code: def __call__(
      self,
      noise_distribution,
      epsilon,
      layers,
      class_weights,
      n_samples,
      batch_size,
  ):
      """Accepts required values for bolton method from context entry point.
  
      Stores them on the optimizer for use throughout fitting.
  
      Args:
        noise_distribution: the noise distribution to pick. see
          _accepted_distributions and get_noise for possible values.
        epsilon: privacy parameter. Lower gives more privacy but less utility.
        layers: list of Keras/Tensorflow layers. Can be found as model.layers
        class_weights: class_weights used, which may either be a scalar or 1D
          tensor with dim == n_classes.
        n_samples: number of rows/individual samples in the training set
        batch_size: batch size used.
  
      Returns:
        self, to be used by the __enter__ method for context.
      """
      if epsilon <= 0:
          raise ValueError(
              "Detected epsilon: {0}. "
              "Valid range is 0 < epsilon <inf".format(epsilon)
          )
      if noise_distribution not in _accepted_distributions:
          raise ValueError(
              "Detected noise distribution: {0} not one of: {1} valid"
              "distributions".format(
                  noise_distribution, _accepted_distributions
              )
          )
      self.noise_distribution = noise_distribution
      self.learning_rate.initialize(
          self.loss.beta(class_weights), self.loss.gamma()
      )
      self.epsilon = tf.constant(epsilon, dtype=self.dtype)
      self.class_weights = tf.constant(class_weights, dtype=self.dtype)
      self.n_samples = tf.constant(n_samples, dtype=self.dtype)
      self.layers = layers
      self.batch_size = tf.constant(batch_size, dtype=self.dtype)
      return self
  
imports: import tensorflow.compat.v1
  from tensorflow.compat.v1.python.keras.optimizer_v2 import optimizer_v2
  from tensorflow.compat.v1.python.ops import math_ops
  from tensorflow_privacy.privacy.bolt_on.losses import StrongConvexMixin
label_desc: Use image node_id 16 for calling the BoltOn obj's underlying member method code with example usage: obj.__call__(noise_distribution, epsilon, layers, class_weights, n_samples, batch_size) and returns: self