class_docstr: Generates a tfp.distribution.Normal by predicting a mean and std.
  
  Note: By default this network uses `tanh_squash_to_spec` to normalize its
  output. Due to the nature of the `tanh` function, values near the spec bounds
  cannot be returned.
  
  Note: The standard deviations are independent of the input.
class_docstr_tok: ["Generates","a","tfp.distribution.Normal","by","predicting","a","mean","and","std",".","Note",":","By","default","this","network","uses","`","tanh_squash_to_spec","`","to","normalize","its","output",".","Due","to","the","nature","of","the","`","tanh","`","function",",","values","near","the","spec","bounds","can","not","be","returned",".","Note",":","The","standard","deviations","are","independent","of","the","input","."]
code: def _output_distribution_spec(self, sample_spec, network_name):
      is_multivariate = sample_spec.shape.ndims > 0
      param_properties = tfp.distributions.Normal.parameter_properties()
      input_param_spec = {  # pylint: disable=g-complex-comprehension
          name: tensor_spec.TensorSpec(
              shape=properties.shape_fn(sample_spec.shape),
              dtype=sample_spec.dtype,
              name=network_name + "_" + name,
          )
          for name, properties in param_properties.items()
      }
  
      def distribution_builder(*args, **kwargs):
          if is_multivariate:
              # For backwards compatibility, and because MVNDiag does not support
              # `param_static_shapes`, even when using MVNDiag the spec
              # continues to use the terms 'loc' and 'scale'.  Here we have to massage
              # the construction to use 'scale' for kwarg 'scale_diag'.  Since they
              # have the same shape and dtype expectationts, this is okay.
              kwargs = kwargs.copy()
              kwargs["scale_diag"] = kwargs["scale"]
              del kwargs["scale"]
              distribution = tfp.distributions.MultivariateNormalDiag(
                  *args, **kwargs
              )
          else:
              distribution = tfp.distributions.Normal(*args, **kwargs)
          if self._scale_distribution:
              return distribution_utils.scale_distribution_to_spec(
                  distribution, sample_spec
              )
          return distribution
  
      return distribution_spec.DistributionSpec(
          distribution_builder,
          input_param_spec,
          sample_spec=sample_spec,
      )
  
file_path: agents/tf_agents/networks/normal_projection_network.py
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import sys
  import gin
  import tensorflow
  import tensorflow_probability
  from tf_agents.distributions import utils
  from tf_agents.keras_layers import bias_layer
  from tf_agents.networks import network
  from tf_agents.networks import utils
  from tf_agents.specs import distribution_spec
  from tf_agents.specs import tensor_spec
label_desc: Use image node_id 2 for calling the NormalProjectionNetwork obj's underlying member method code with example usage: obj._output_distribution_spec(sample_spec, network_name) and returns: distribution_spec, distribution, distribution_utils