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: Sample noise to be added to weights for privacy guarantee.
  
  Args:
    input_dim: the input dimensionality for the weights
    output_dim: the output dimensionality for the weights
  
  Returns:
    Noise in shape of layer's weights to be added to the weights.
  
  Raises:
    Exception: If not called from inside this optimizer's context.
docstr_tok: ["Sample","noise","to","be","added","to","weights","for","privacy","guarantee",".","Args",":","input_dim",":","the","input","dimensionality","for","the","weights","output_dim",":","the","output","dimensionality","for","the","weights","Returns",":","Noise","in","shape","of","layer","'s","weights","to","be","added","to","the","weights",".","Raises",":","Exception",":","If","not","called","from","inside","this","optimizer","'s","context","."]
code: def get_noise(self, input_dim, output_dim):
      """Sample noise to be added to weights for privacy guarantee.
  
      Args:
        input_dim: the input dimensionality for the weights
        output_dim: the output dimensionality for the weights
  
      Returns:
        Noise in shape of layer's weights to be added to the weights.
  
      Raises:
        Exception: If not called from inside this optimizer's context.
      """
      if not self._is_init:
          raise Exception(
              "This method must be called from within the optimizer's "
              "context."
          )
      loss = self.loss
      distribution = self.noise_distribution.lower()
      if distribution == _accepted_distributions[0]:  # laplace
          per_class_epsilon = self.epsilon / (output_dim)
          l2_sensitivity = (
              2 * loss.lipchitz_constant(self.class_weights)
          ) / (loss.gamma() * self.n_samples * self.batch_size)
          unit_vector = tf.random.normal(
              shape=(input_dim, output_dim),
              mean=0,
              seed=1,
              stddev=1.0,
              dtype=self.dtype,
          )
          unit_vector = unit_vector / tf.math.sqrt(
              tf.reduce_sum(tf.math.square(unit_vector), axis=0)
          )
  
          beta = l2_sensitivity / per_class_epsilon
          alpha = input_dim  # input_dim
          gamma = tf.random.gamma(
              [output_dim],
              alpha,
              beta=1 / beta,
              seed=1,
              dtype=self.dtype,
          )
          return unit_vector * gamma
      raise NotImplementedError(
          "Noise distribution: {0} is not "
          "a valid distribution".format(distribution)
      )
  
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 4 for calling the BoltOn obj's underlying member method code with example usage: obj.get_noise(input_dim, output_dim) and returns: unknown