class_docstr: Empirical distribution.
  
  The Empirical distribution is parameterized by a [batch] multiset of samples.
  It describes the empirical measure (observations) of a variable.
  
  Note: some methods (log_prob, prob, cdf, mode, entropy) are not differentiable
  with regard to samples.
  
  #### Mathematical Details
  
  The probability mass function (pmf) and cumulative distribution function (cdf)
  are
  
  ```none
  pmf(k; s1, ..., sn) = sum_i I(k)^{k == si} / n
  I(k)^{k == si} == 1, if k == si, else 0.
  cdf(k; s1, ..., sn) = sum_i I(k)^{k >= si} / n
  I(k)^{k >= si} == 1, if k >= si, else 0.
  ```
  
  #### Examples
  
  ```python
  
  # Initialize a empirical distribution with 4 scalar samples.
  dist = Empirical(samples=[0., 1., 1., 2.])
  dist.cdf(1.)
  ==> 0.75
  dist.prob([0., 1.])
  ==> [0.25, 0.5] # samples will be broadcast to
                    [[0., 1., 1., 2.], [0., 1., 1., 2.]] to match event.
  
  # Initialize a empirical distribution with a [2] batch of scalar samples.
  dist = Empirical(samples=[[0., 1.], [1., 2.]])
  dist.cdf([0., 2.])
  ==> [0.5, 1.]
  dist.prob(0.)
  ==> [0.5, 0] # event will be broadcast to [0., 0.] to match samples.
  
  # Initialize a empirical distribution with 4 vector-like samples.
  dist = Empirical(samples=[[0., 0.], [0., 1.], [0., 1.], [1., 2.]],
                   event_ndims=1)
  dist.cdf([0., 1.])
  ==> 0.75
  dist.prob([[0., 1.], [1., 2.]])
  ==> [0.5, 0.25] # samples will be broadcast to shape [2, 4, 2] to match event.
  
  # Initialize a empirical distribution with a [2] batch of vector samples.
  dist = Empirical(samples=[[[0., 0.], [0., 1.]], [[0., 1.], [1., 2.]]],
                   event_ndims=1)
  dist.cdf([[0., 0.], [0., 1.]])
  ==> [0.5, 0.5]
  dist.prob([0., 1.])
  ==> [0.5, 1.] # event will be broadcast to shape [[0., 1.], [0., 1.]]
                  to match samples.
  ```
code: def _mode(self, samples=None):
      # Samples count can vary by batch member. Use map_fn to compute mode for
      # each batch separately.
      def _get_mode(samples):
          _, idx, count = tf.raw_ops.UniqueWithCountsV2(
              x=samples, axis=[0]
          )
          # TODO(b/161402486): Remove this hack for fixing the wrong static shape
          # of `idx` in graph mode.
          idx = tf.vectorized_map(lambda x: tf.reshape(x, [-1])[0], idx)
          # NOTE:
          #  - `count` has shape `[K]`, where `K` is the number of unique elements,
          #    and `count[j]` is the number of times the j-th unique element occurs
          #    in `samples`.
          #  - `idx` has shape `[samples.shape[0]]`, and `idx[i] == j` means that
          #    `samples[i]` is equal to the `j`-th unique element.
          max_count_idx = tf.argmax(count, output_type=tf.int32)
          # Return an index `i` for which `idx[i] == max_count_idx`.
          return tf.argmax(
              tf.cast(
                  tf.math.equal(idx, max_count_idx), dtype=tf.int32
              ),
              output_type=tf.int32,
          )
  
      if samples is None:
          samples = tf.convert_to_tensor(self._samples)
      num_samples = self._compute_num_samples(samples)
  
      # Flatten samples for each batch.
      if self._event_ndims == 0:
          flattened_samples = tf.reshape(samples, [-1, num_samples])
          mode_shape = self._batch_shape_tensor(samples=samples)
      else:
          event_size = tf.reduce_prod(self._event_shape_tensor(samples))
          mode_shape = ps.concat(
              [
                  self._batch_shape_tensor(samples=samples),
                  self._event_shape_tensor(samples=samples),
              ],
              axis=0,
          )
          flattened_samples = tf.reshape(
              samples, [-1, num_samples, event_size]
          )
  
      indices = tf.map_fn(
          _get_mode, flattened_samples, fn_output_signature=tf.int32
      )
      full_indices = tf.stack(
          [tf.range(tf.shape(indices)[0]), indices], axis=1
      )
  
      mode = tf.gather_nd(flattened_samples, full_indices)
      return tf.reshape(mode, mode_shape)
  
imports: import tensorflow.compat.v2
  from tensorflow_probability.python.distributions import distribution
  from tensorflow_probability.python.internal import assert_util
  from tensorflow_probability.python.internal import distribution_util
  from tensorflow_probability.python.internal import dtype_util
  from tensorflow_probability.python.internal import parameter_properties
  from tensorflow_probability.python.internal import prefer_static
  from tensorflow_probability.python.internal import reparameterization
  from tensorflow_probability.python.internal import samplers
  from tensorflow_probability.python.internal import tensor_util
  from tensorflow_probability.python.internal import tensorshape_util
label_desc: Use image node_id 12 for calling the Empirical obj's underlying member method code with example usage: obj._mode(samples) and returns: tf, tf