class_docstr: A factorized Noisy Net layer
  
  https://arxiv.org/abs/1706.10295.
class_docstr_tok: ["A","factorized","Noisy","Net","layer","https",":","\/\/arxiv.org\/abs\/1706.10295","."]
docstr: returns a NoisyNet dense layer
  :param input_layer: previous layer
  :param name: layer name
  :param kernel_initializer: initializer for kernels. Default is to use Gaussian noise that preserves stddev.
  :param activation: the activation function
  :return: dense layer
docstr_tok: ["returns","a","NoisyNet","dense","layer",":","param","input_layer",":","previous","layer",":","param","name",":","layer","name",":","param","kernel_initializer",":","initializer","for","kernels",".","Default","is","to","use","Gaussian","noise","that","preserves","stddev",".",":","param","activation",":","the","activation","function",":","return",":","dense","layer"]
code: def __call__(
      self,
      input_layer,
      name: str,
      kernel_initializer=None,
      activation=None,
      is_training=None,
      bias_initializer=None,
  ):
      """
      returns a NoisyNet dense layer
      :param input_layer: previous layer
      :param name: layer name
      :param kernel_initializer: initializer for kernels. Default is to use Gaussian noise that preserves stddev.
      :param activation: the activation function
      :return: dense layer
      """
      # TODO: noise sampling should be externally controlled. DQN is fine with sampling noise for every
      #      forward (either act or train, both for online and target networks).
      #      A3C, on the other hand, should sample noise only when policy changes (i.e. after every t_max steps)
  
      def _f(values):
          return tf.sqrt(tf.abs(values)) * tf.sign(values)
  
      def _factorized_noise(inputs, outputs):
          # TODO: use factorized noise only for compute intensive algos (e.g. DQN).
          #      lighter algos (e.g. DQN) should not use it
          noise1 = _f(tf.random_normal((inputs, 1)))
          noise2 = _f(tf.random_normal((1, outputs)))
          return tf.matmul(noise1, noise2)
  
      num_inputs = input_layer.get_shape()[-1].value
      num_outputs = self.units
  
      stddev = 1 / math.sqrt(num_inputs)
      activation = (
          activation if activation is not None else (lambda x: x)
      )
  
      if kernel_initializer is None:
          kernel_mean_initializer = tf.random_uniform_initializer(
              -stddev, stddev
          )
          kernel_stddev_initializer = tf.random_uniform_initializer(
              -stddev * self.sigma0, stddev * self.sigma0
          )
      else:
          kernel_mean_initializer = (
              kernel_stddev_initializer
          ) = kernel_initializer
      if bias_initializer is None:
          bias_initializer = tf.zeros_initializer()
      with tf.variable_scope(None, default_name=name):
          weight_mean = tf.get_variable(
              "weight_mean",
              shape=(num_inputs, num_outputs),
              initializer=kernel_mean_initializer,
          )
          bias_mean = tf.get_variable(
              "bias_mean",
              shape=(num_outputs,),
              initializer=bias_initializer,
          )
  
          weight_stddev = tf.get_variable(
              "weight_stddev",
              shape=(num_inputs, num_outputs),
              initializer=kernel_stddev_initializer,
          )
          bias_stddev = tf.get_variable(
              "bias_stddev",
              shape=(num_outputs,),
              initializer=kernel_stddev_initializer,
          )
          bias_noise = _f(tf.random_normal((num_outputs,)))
          weight_noise = _factorized_noise(num_inputs, num_outputs)
  
      bias = bias_mean + bias_stddev * bias_noise
      weight = weight_mean + weight_stddev * weight_noise
      return activation(tf.matmul(input_layer, weight) + bias)
  
imports: import math
  from types import FunctionType
  import tensorflow
  from rl_coach.architectures import layers
  from rl_coach.architectures.tensorflow_components import utils
label_desc: Use image node_id 2 for calling the NoisyNetDense obj's underlying member method code with example usage: obj.__call__(input_layer, name, kernel_initializer, activation, is_training, bias_initializer) and returns: activation, unknown, tf