def sample(self, sample_shape=(), seed=None, name=None):
     with tf.name_scope(name or 'sample_particles'):
         sample_shape = prefer_static.concat([
             dist_util.expand_to_vector(sample_shape), [self.num_particles]
         ],
                                             axis=0)
         return self.distribution.sample(sample_shape, seed=seed)
  def sample(self, sample_shape=(), seed=None, name=None):
    with tf.name_scope(name or 'sample'):
      # Grab the required number of values from the provided tensors.
      sample_shape = dist_util.expand_to_vector(sample_shape)
      n = tf.cast(tf.reduce_prod(sample_shape), dtype=tf.int32)

      # Check that we're not trying to draw too many samples.
      assertions = []
      will_overflow_ = tf.get_static_value(n > self.max_num_samples)
      if will_overflow_:
        raise ValueError('Trying to draw {} samples from a '
                         '`DeterministicEmpirical` instance for which only {} '
                         'samples were provided.'.format(
                             tf.get_static_value(n),
                             tf.get_static_value(self.max_num_samples)))
      elif (will_overflow_ is None  # Couldn't determine statically.
            and self.validate_args):
        assertions.append(
            tf.debugging.assert_less_equal(
                n, self.max_num_samples, message='Number of samples to draw '
                'from a `DeterministicEmpirical` instance must not exceed the '
                'number provided at construction.'))

      # Extract the appropriate number of sampled values.
      with tf.control_dependencies(assertions):
        sampled = tf.nest.map_structure(
            lambda x: x[:n, ...], self.values_with_sample_dim)

      # Reshape the values to the appropriate sample shape.
      return tf.nest.map_structure(
          lambda x: tf.reshape(x,  # pylint: disable=g-long-lambda
                               tf.concat([tf.cast(sample_shape, tf.int32),
                                          tf.cast(tf.shape(x)[1:], tf.int32)],
                                         axis=0)),
          sampled)
Exemple #3
0
  def new(params, event_shape=(), given_log_count=True,
          validate_args=False, name=None):
    """Create the distribution instance from a `params` vector."""
    from odin.bay.distributions import ZeroInflated

    with tf.compat.v1.name_scope(name, 'ZeroInflatedNegativeBinomial',
                                 [params, event_shape]):
      params = tf.convert_to_tensor(value=params, name='params')
      event_shape = dist_util.expand_to_vector(
          tf.convert_to_tensor(
              value=event_shape, name='event_shape', dtype=tf.int32),
          tensor_name='event_shape')
      output_shape = tf.concat([
          tf.shape(input=params)[:-1],
          event_shape,
      ], axis=0)
      (total_count_params, logits_params,
       rate_params) = tf.split(params, 3, axis=-1)
      if given_log_count:
        total_count_params = tf.exp(total_count_params, name='total_count')
      nb = tfd.NegativeBinomial(
          total_count=tf.reshape(total_count_params, output_shape),
          logits=tf.reshape(logits_params, output_shape),
          validate_args=validate_args)
      zinb = ZeroInflated(count_distribution=nb,
                          logits=tf.reshape(rate_params, output_shape),
                          validate_args=validate_args)
      return tfd.Independent(zinb,
          reinterpreted_batch_ndims=tf.size(input=event_shape),
          validate_args=validate_args)
Exemple #4
0
 def new(params,
         temperature,
         probs_input=False,
         event_shape=(),
         validate_args=False,
         name='RelaxedBernoulliLayer'):
   """Create the distribution instance from a `params` vector."""
   params = tf.convert_to_tensor(value=params, name='params')
   event_shape = dist_util.expand_to_vector(
       tf.convert_to_tensor(value=event_shape,
                            name='event_shape',
                            dtype_hint=tf.int32),
       tensor_name='event_shape',
   )
   new_shape = tf.concat(
       [tf.shape(input=params)[:-1], event_shape],
       axis=0,
   )
   params = tf.reshape(params, new_shape)
   dist = tfd.Independent(
       tfd.RelaxedBernoulli(temperature=temperature,
                            logits=None if probs_input else params,
                            probs=params if probs_input else None,
                            validate_args=validate_args),
       reinterpreted_batch_ndims=tf.size(input=event_shape),
       name=name,
   )
   return dist
Exemple #5
0
  def __init__(
      self,
      distribution,
      sample_shape=(),
      validate_args=False,
      name=None):
    """Construct the `Sample` distribution.

    Args:
      distribution: The base distribution instance to transform. Typically an
        instance of `Distribution`.
      sample_shape: `int` scalar or vector `Tensor` representing the shape of a
        single sample.
      validate_args: Python `bool`.  Whether to validate input with asserts.
        If `validate_args` is `False`, and the inputs are invalid,
        correct behavior is not guaranteed.
      name: The name for ops managed by the distribution.
        Default value: `None` (i.e., `'Sample' + distribution.name`).
    """
    parameters = dict(locals())
    name = name or 'Sample' + distribution.name
    self._distribution = distribution
    with tf.compat.v1.name_scope(name) as name:
      sample_shape = distribution_util.expand_to_vector(tf.convert_to_tensor(
          value=sample_shape, dtype_hint=tf.int32, name='sample_shape'))
      self._sample_shape = sample_shape
      super(Sample, self).__init__(
          dtype=self._distribution.dtype,
          reparameterization_type=self._distribution.reparameterization_type,
          validate_args=validate_args,
          allow_nan_stats=self._distribution.allow_nan_stats,
          parameters=parameters,
          graph_parents=([sample_shape] + distribution._graph_parents),  # pylint: disable=protected-access
          name=name)
Exemple #6
0
 def __init__(self,
              distribution,
              batch_stack=(),
              validate_args=False,
              name=None):
     """Construct the `BatchStacker` distribution.
     Args:
     distribution: The base distribution instance to transform. Typically an
         instance of `Distribution`.
     batch_stack: `int` scalar or vector `Tensor` representing the shape of a
         single sample.
     validate_args: Python `bool`.  Whether to validate input with asserts.
         If `validate_args` is `False`, and the inputs are invalid,
         correct behavior is not guaranteed.
     name: The name for ops managed by the distribution.
         Default value: `None` (i.e., `'BatchStacker' + distribution.name`).
     """
     parameters = dict(locals())
     name = name or "BatchStacker" + distribution.name
     self._distribution = distribution
     with tf.name_scope(name) as name:
         batch_stack = distribution_util.expand_to_vector(
             tf.convert_to_tensor(batch_stack,
                                  dtype_hint=tf.int32,
                                  name="batch_stack"))
         self._batch_stack = batch_stack
         super(BatchStacker, self).__init__(
             dtype=self._distribution.dtype,
             reparameterization_type=self._distribution.
             reparameterization_type,
             validate_args=validate_args,
             allow_nan_stats=self._distribution.allow_nan_stats,
             parameters=parameters,
             name=name,
         )
Exemple #7
0
 def new(params,
         event_shape=(),
         dtype=None,
         validate_args=False,
         name='BernoulliLayer'):
   r"""Create the distribution instance from a `params` vector."""
   params = tf.convert_to_tensor(value=params, name='params')
   event_shape = dist_util.expand_to_vector(
       tf.convert_to_tensor(value=event_shape,
                            name='event_shape',
                            dtype_hint=tf.int32),
       tensor_name='event_shape',
   )
   new_shape = tf.concat(
       [tf.shape(input=params)[:-1], event_shape],
       axis=0,
   )
   dist = tfd.Independent(
       tfd.Bernoulli(logits=tf.reshape(params, new_shape),
                     dtype=dtype or params.dtype.base_dtype,
                     validate_args=validate_args),
       reinterpreted_batch_ndims=tf.size(input=event_shape),
       name=name,
   )
   dist.logits = dist.distribution._logits  # pylint: disable=protected-access
   dist.probs = dist.distribution._probs  # pylint: disable=protected-access
   return dist
Exemple #8
0
 def new(params,
         event_shape=(),
         mean_activation=tf.nn.softplus,
         disp_activation=softplus1,
         validate_args=False,
         name="NegativeBinomialDispLayer",
         disp=None):
     r""" Create the distribution instance from a `params` vector. """
     params = tf.convert_to_tensor(value=params, name='params')
     event_shape = dist_util.expand_to_vector(
         tf.convert_to_tensor(value=event_shape,
                              name='event_shape',
                              dtype=tf.int32),
         tensor_name='event_shape',
     )
     output_shape = tf.concat(
         [tf.shape(input=params)[:-1], event_shape],
         axis=0,
     )
     if disp is None:
         loc, disp = tf.split(params, 2, axis=-1)
         disp = tf.reshape(disp, output_shape)
     else:
         loc = params
     loc = tf.reshape(loc, output_shape)
     loc = mean_activation(loc)
     disp = disp_activation(disp)
     return tfd.Independent(
         NegativeBinomialDisp(loc=loc,
                              disp=disp,
                              validate_args=validate_args),
         reinterpreted_batch_ndims=tf.size(input=event_shape),
         name=name,
     )
Exemple #9
0
    def new(params,
            event_shape=(),
            given_log_count=True,
            validate_args=False,
            name=None):
        """Create the distribution instance from a `params` vector."""
        from odin.bay.distributions import ZeroInflated

        with tf.compat.v1.name_scope(name, 'ZeroInflatedNegativeBinomial',
                                     [params, event_shape]):
            params = tf.convert_to_tensor(value=params, name='params')
            event_shape = dist_util.expand_to_vector(tf.convert_to_tensor(
                value=event_shape, name='event_shape', dtype=tf.int32),
                                                     tensor_name='event_shape')
            output_shape = tf.concat([
                tf.shape(input=params)[:-1],
                event_shape,
            ],
                                     axis=0)
            (total_count_params, logits_params,
             rate_params) = tf.split(params, 3, axis=-1)
            if given_log_count:
                total_count_params = tf.exp(total_count_params,
                                            name='total_count')
            nb = tfd.NegativeBinomial(
                total_count=tf.reshape(total_count_params, output_shape),
                logits=tf.reshape(logits_params, output_shape),
                validate_args=validate_args)
            zinb = ZeroInflated(count_distribution=nb,
                                logits=tf.reshape(rate_params, output_shape),
                                validate_args=validate_args)
            return tfd.Independent(
                zinb,
                reinterpreted_batch_ndims=tf.size(input=event_shape),
                validate_args=validate_args)
Exemple #10
0
 def new(params,
         event_shape=(),
         alpha_activation=tf.nn.softplus,
         beta_activation=tf.nn.softplus,
         clip_for_stable=True,
         validate_args=False,
         name="BetaLayer"):
     r"""Create the distribution instance from a `params` vector."""
     params = tf.convert_to_tensor(value=params, name='params')
     alpha_activation = parse_activation(alpha_activation, 'tf')
     beta_activation = parse_activation(beta_activation, 'tf')
     event_shape = dist_util.expand_to_vector(
         tf.convert_to_tensor(value=event_shape,
                              name='event_shape',
                              dtype=tf.int32),
         tensor_name='event_shape',
     )
     output_shape = tf.concat(
         [tf.shape(input=params)[:-1], event_shape],
         axis=0,
     )
     # alpha, beta
     concentration1, concentration0 = tf.split(params, 2, axis=-1)
     concentration1 = alpha_activation(concentration1)
     concentration0 = beta_activation(concentration0)
     if clip_for_stable:
         concentration0 = tf.clip_by_value(concentration0, 1e-3, 1e3)
         concentration1 = tf.clip_by_value(concentration1, 1e-3, 1e3)
     return tfd.Independent(
         tfd.Beta(concentration1=tf.reshape(concentration1, output_shape),
                  concentration0=tf.reshape(concentration0, output_shape),
                  validate_args=validate_args),
         reinterpreted_batch_ndims=tf.size(input=event_shape),
         name=name,
     )
Exemple #11
0
 def new(params,
         event_shape=(),
         softplus_scale=True,
         validate_args=False,
         name=None):
     """Create the distribution instance from a `params` vector."""
     with tf.compat.v1.name_scope(name, 'LogNormal', [params, event_shape]):
         params = tf.convert_to_tensor(value=params, name='params')
         event_shape = dist_util.expand_to_vector(tf.convert_to_tensor(
             value=event_shape, name='event_shape', dtype=tf.int32),
                                                  tensor_name='event_shape')
         output_shape = tf.concat([
             tf.shape(input=params)[:-1],
             event_shape,
         ],
                                  axis=0)
         loc_params, scale_params = tf.split(params, 2, axis=-1)
         if softplus_scale:
             scale_params = tf.math.softplus(
                 scale_params) + tfd.softplus_inverse(1.0)
         return tfd.Independent(
             tfd.LogNormal(loc=tf.reshape(loc_params, output_shape),
                           scale=tf.reshape(scale_params, output_shape),
                           validate_args=validate_args),
             reinterpreted_batch_ndims=tf.size(input=event_shape),
             validate_args=validate_args)
Exemple #12
0
    def new(params, event_shape=(), validate_args=False, name=None):
        """Create the distribution instance from a `params` vector."""
        from odin.bay.distributions import ZeroInflated

        with tf.compat.v1.name_scope(name, 'ZeroInflatedPoisson',
                                     [params, event_shape]):
            params = tf.convert_to_tensor(value=params, name='params')
            event_shape = dist_util.expand_to_vector(tf.convert_to_tensor(
                value=event_shape, name='event_shape', dtype=tf.int32),
                                                     tensor_name='event_shape')
            output_shape = tf.concat([
                tf.shape(input=params)[:-1],
                event_shape,
            ],
                                     axis=0)
            (log_rate_params, logits_params) = tf.split(params, 2, axis=-1)
            zip = ZeroInflated(count_distribution=tfd.Poisson(
                log_rate=tf.reshape(log_rate_params, output_shape),
                validate_args=validate_args),
                               logits=tf.reshape(logits_params, output_shape),
                               validate_args=validate_args)
            return tfd.Independent(
                zip,
                reinterpreted_batch_ndims=tf.size(input=event_shape),
                validate_args=validate_args)
 def new(params,
         event_shape=(),
         log_prob=None,
         reinterpreted_batch_ndims=None,
         validate_args=False,
         name='DeterministicLayer'):
     """Create the distribution instance from a `params` vector."""
     params = tf.convert_to_tensor(value=params, name='params')
     event_shape = dist_util.expand_to_vector(
         tf.convert_to_tensor(value=event_shape,
                              name='event_shape',
                              dtype=tf.int32),
         tensor_name='event_shape',
     )
     output_shape = tf.concat(
         [tf.shape(input=params)[:-1], event_shape],
         axis=0,
     )
     dist = tfd.Deterministic(loc=tf.reshape(params, output_shape),
                              validate_args=validate_args,
                              name=name)
     # override the log-prob function
     if log_prob is not None and callable(log_prob):
         dist.log_prob = types.MethodType(log_prob, dist)
     # independent
     if reinterpreted_batch_ndims is not None and reinterpreted_batch_ndims > 0:
         dist = tfd.Independent(
             dist, reinterpreted_batch_ndims=int(reinterpreted_batch_ndims))
     return dist
Exemple #14
0
 def new(params,
         event_shape='auto',
         pre_softplus=False,
         clip_for_stable=True,
         validate_args=False,
         name=None):
     """Create the distribution instance from a `params` vector."""
     event_shape = _preprocess_eventshape(params, event_shape)
     with tf.compat.v1.name_scope(name, 'Dirichlet', [params, event_shape]):
         params = tf.convert_to_tensor(value=params, name='params')
         event_shape = dist_util.expand_to_vector(tf.convert_to_tensor(
             value=event_shape, name='event_shape', dtype=tf.int32),
                                                  tensor_name='event_shape')
         output_shape = tf.concat([
             tf.shape(input=params)[:-1],
             event_shape,
         ],
                                  axis=0)
         # Clips the Dirichlet parameters to the numerically stable KL region
         if pre_softplus:
             params = tf.nn.softplus(params)
         if clip_for_stable:
             params = tf.clip_by_value(params, 1e-3, 1e3)
         return tfd.Independent(
             tfd.Dirichlet(concentration=tf.reshape(params, output_shape),
                           validate_args=validate_args),
             reinterpreted_batch_ndims=tf.size(input=event_shape),
             validate_args=validate_args)
Exemple #15
0
 def new(params,
         event_shape=(),
         count_activation=tf.nn.softplus,
         validate_args=False,
         name='BinomialLayer'):
     r"""Create the distribution instance from a `params` vector."""
     count_activation = parse_activation(count_activation, 'tf')
     params = tf.convert_to_tensor(value=params, name='params')
     event_shape = dist_util.expand_to_vector(
         tf.convert_to_tensor(value=event_shape,
                              name='event_shape',
                              dtype=tf.int32),
         tensor_name='event_shape',
     )
     output_shape = tf.concat((tf.shape(params)[:-1], event_shape), axis=0)
     total_count, logits = tf.split(params, 2, axis=-1)
     total_count = tf.reshape(total_count, output_shape)
     logits = tf.reshape(logits, output_shape)
     return tfd.Independent(
         tfd.Binomial(total_count=count_activation(total_count),
                      logits=logits,
                      validate_args=validate_args),
         reinterpreted_batch_ndims=tf.size(event_shape),
         name=name,
     )
Exemple #16
0
 def new(params,
         event_shape=(),
         activation=tf.identity,
         validate_args=False,
         name="ZIPoissonLayer"):
     """Create the distribution instance from a `params` vector."""
     params = tf.convert_to_tensor(value=params, name='params')
     event_shape = dist_util.expand_to_vector(
         tf.convert_to_tensor(value=event_shape,
                              name='event_shape',
                              dtype=tf.int32),
         tensor_name='event_shape',
     )
     output_shape = tf.concat(
         [tf.shape(input=params)[:-1], event_shape],
         axis=0,
     )
     (log_rate_params, logits_params) = tf.split(params, 2, axis=-1)
     return tfd.Independent(
         ZeroInflated(count_distribution=tfd.Poisson(
             log_rate=activation(tf.reshape(log_rate_params, output_shape)),
             validate_args=validate_args),
                      logits=tf.reshape(logits_params, output_shape),
                      validate_args=validate_args),
         reinterpreted_batch_ndims=tf.size(input=event_shape),
         name=name,
     )
Exemple #17
0
 def new(params,
         event_shape,
         concentration_activation=softplus1,
         rate_activation=softplus1,
         validate_args=False,
         name="GammaLayer"):
   """Create the distribution instance from a `params` vector."""
   params = tf.convert_to_tensor(value=params, name='params')
   event_shape = dist_util.expand_to_vector(
       tf.convert_to_tensor(value=event_shape,
                            name='event_shape',
                            dtype=tf.int32),
       tensor_name='event_shape',
   )
   output_shape = tf.concat((tf.shape(input=params)[:-1], event_shape), axis=0)
   concentration, rate = tf.split(params, 2, axis=-1)
   concentration = tf.reshape(concentration, output_shape)
   concentration = concentration_activation(concentration)
   rate = tf.reshape(rate, output_shape)
   rate = rate_activation(rate)
   return tfd.Independent(
       tfd.Gamma(concentration=concentration,
                 rate=rate,
                 validate_args=validate_args),
       reinterpreted_batch_ndims=tf.size(input=event_shape),
       name=name,
   )
Exemple #18
0
 def new(params,
         event_shape=(),
         given_logits=True,
         validate_args=False,
         name='ZIBernoulliLayer'):
   """Create the distribution instance from a `params` vector."""
   params = tf.convert_to_tensor(value=params, name='params')
   event_shape = dist_util.expand_to_vector(
       tf.convert_to_tensor(value=event_shape,
                            name='event_shape',
                            dtype=tf.int32),
       tensor_name='event_shape',
   )
   output_shape = tf.concat(
       [tf.shape(input=params)[:-1], event_shape],
       axis=0,
   )
   (bernoulli_params, rate_params) = tf.split(params, 2, axis=-1)
   bernoulli_params = tf.reshape(bernoulli_params, output_shape)
   bern = tfd.Bernoulli(logits=bernoulli_params if given_logits else None,
                        probs=bernoulli_params if not given_logits else None,
                        validate_args=validate_args)
   zibern = ZeroInflated(count_distribution=bern,
                         logits=tf.reshape(rate_params, output_shape),
                         validate_args=validate_args)
   return tfd.Independent(zibern,
                          reinterpreted_batch_ndims=tf.size(input=event_shape),
                          name=name)
Exemple #19
0
 def new(params,
         event_shape=(),
         dtype=None,
         validate_args=False,
         name=None):
     """Create the distribution instance from a `params` vector."""
     with tf.name_scope(name, 'IndependentBernoulli',
                        [params, event_shape]):
         params = tf.convert_to_tensor(params, name='params')
         event_shape = dist_util.expand_to_vector(tf.convert_to_tensor(
             event_shape, name='event_shape', preferred_dtype=tf.int32),
                                                  tensor_name='event_shape')
         new_shape = tf.concat([
             tf.shape(params)[:-1],
             event_shape,
         ],
                               axis=0)
         dist = tfd.Independent(
             tfd.Bernoulli(logits=tf.reshape(params, new_shape),
                           dtype=dtype or params.dtype.base_dtype,
                           validate_args=validate_args),
             reinterpreted_batch_ndims=tf.size(event_shape),
             validate_args=validate_args)
         dist._logits = dist.distribution._logits  # pylint: disable=protected-access
         dist._probs = dist.distribution._probs  # pylint: disable=protected-access
         dist.logits = tfd.Bernoulli.logits
         dist.probs = tfd.Bernoulli.probs
         return dist
Exemple #20
0
 def new(params,
         event_shape=(),
         count_activation=tf.exp,
         validate_args=False,
         name="NegativeBinomialLayer",
         disp=None):
     r"""Create the distribution instance from a `params` vector."""
     params = tf.convert_to_tensor(value=params, name='params')
     event_shape = dist_util.expand_to_vector(
         tf.convert_to_tensor(value=event_shape,
                              name='event_shape',
                              dtype=tf.int32),
         tensor_name='event_shape',
     )
     output_shape = tf.concat(
         [tf.shape(input=params)[:-1], event_shape],
         axis=0,
     )
     if disp is None:
         total_count, logits = tf.split(params, 2, axis=-1)
         logits = tf.reshape(logits, output_shape)
     else:
         total_count = params
         logits = disp
     total_count = tf.reshape(total_count, output_shape)
     total_count = count_activation(total_count)
     return tfd.Independent(
         tfd.NegativeBinomial(total_count=total_count,
                              logits=logits,
                              validate_args=validate_args),
         reinterpreted_batch_ndims=tf.size(input=event_shape),
         name=name,
     )
Exemple #21
0
 def new(params,
         event_shape,
         loc_activation,
         scale_activation,
         validate_args=False,
         name="LogNormalLayer"):
   """Create the distribution instance from a `params` vector."""
   params = tf.convert_to_tensor(value=params, name='params')
   event_shape = dist_util.expand_to_vector(
       tf.convert_to_tensor(value=event_shape,
                            name='event_shape',
                            dtype=tf.int32),
       tensor_name='event_shape',
   )
   output_shape = tf.concat(
       [tf.shape(input=params)[:-1], event_shape],
       axis=0,
   )
   loc_params, scale_params = tf.split(params, 2, axis=-1)
   loc_params = tf.reshape(loc_activation(loc_params), output_shape)
   scale_params = tf.reshape(scale_activation(scale_params), output_shape)
   return tfd.Independent(
       tfd.LogNormal(loc=loc_params,
                     scale=scale_params,
                     validate_args=validate_args),
       reinterpreted_batch_ndims=tf.size(input=event_shape),
       name=name,
   )
Exemple #22
0
  def new(params, event_shape=(), validate_args=False, name=None):
    """Create the distribution instance from a `params` vector."""
    from odin.bay.distributions import ZeroInflated

    with tf.compat.v1.name_scope(name, 'ZeroInflatedPoisson',
                                 [params, event_shape]):
      params = tf.convert_to_tensor(value=params, name='params')
      event_shape = dist_util.expand_to_vector(
          tf.convert_to_tensor(
              value=event_shape, name='event_shape', dtype=tf.int32),
          tensor_name='event_shape')
      output_shape = tf.concat([
          tf.shape(input=params)[:-1],
          event_shape,
      ], axis=0)
      (log_rate_params, logits_params) = tf.split(params, 2, axis=-1)
      zip = ZeroInflated(
          count_distribution=tfd.Poisson(
              log_rate=tf.reshape(log_rate_params, output_shape),
              validate_args=validate_args),
          logits=tf.reshape(logits_params, output_shape),
          validate_args=validate_args)
      return tfd.Independent(zip,
          reinterpreted_batch_ndims=tf.size(input=event_shape),
          validate_args=validate_args)
def iid_sample(sample_fn, sample_shape):
  """Lift a sampling function to one that draws multiple iid samples.

  Args:
    sample_fn: Python `callable` that returns a (possibly nested) structure of
      `Tensor`s. May optionally take a `seed` named arg: if so, any `int`
      seeds (for stateful samplers) are passed through directly, while any
      pair-of-`int` seeds (for stateless samplers) are split into independent
      seeds for each sample.
    sample_shape: `int` `Tensor` shape of iid samples to draw.
  Returns:
    iid_sample_fn: Python `callable` taking the same arguments as `sample_fn`
      and returning iid samples. Each returned `Tensor` will have shape
      `concat([sample_shape, shape_of_original_returned_tensor])`.
  """
  sample_shape = distribution_util.expand_to_vector(
      ps.cast(sample_shape, np.int32), tensor_name='sample_shape')
  n = ps.cast(ps.reduce_prod(sample_shape), dtype=np.int32)

  def unflatten(x):
    unflattened_shape = ps.cast(
        ps.concat([sample_shape, ps.shape(x)[1:]], axis=0),
        dtype=np.int32)
    return tf.reshape(x, unflattened_shape)

  def iid_sample_fn(*args, **kwargs):
    """Draws iid samples from `fn`."""

    with tf.name_scope('iid_sample_fn'):

      seed = kwargs.pop('seed', None)
      if samplers.is_stateful_seed(seed):
        kwargs = dict(kwargs, seed=SeedStream(seed, salt='iid_sample')())
        def pfor_loop_body(_):
          with tf.name_scope('iid_sample_fn_stateful_body'):
            return sample_fn(*args, **kwargs)
      else:
        # If a stateless seed arg is passed, split it into `n` different
        # stateless seeds, so that we don't just get a bunch of copies of the
        # same sample.
        if not JAX_MODE:
          warnings.warn(
              'Saw Tensor seed {}, implying stateless sampling. Autovectorized '
              'functions that use stateless sampling may be quite slow because '
              'the current implementation falls back to an explicit loop. This '
              'will be fixed in the future. For now, you will likely see '
              'better performance from stateful sampling, which you can invoke '
              'by passing a Python `int` seed.'.format(seed))
        seed = samplers.split_seed(seed, n=n, salt='iid_sample_stateless')
        def pfor_loop_body(i):
          with tf.name_scope('iid_sample_fn_stateless_body'):
            return sample_fn(*args, seed=tf.gather(seed, i), **kwargs)

      draws = parallel_for.pfor(pfor_loop_body, n)
      return tf.nest.map_structure(unflatten, draws, expand_composites=True)

  return iid_sample_fn
Exemple #24
0
def iid_sample(sample_fn, sample_shape):
    """Lift a sampling function to one that draws multiple iid samples.

  Args:
    sample_fn: Python `callable` that returns a (possibly nested) structure of
      `Tensor`s. May optionally take a `seed` named arg: if so, any `int`
      seeds (for stateful samplers) are passed through directly, while any
      pair-of-`int` seeds (for stateless samplers) are split into independent
      seeds for each sample.
    sample_shape: `int` `Tensor` shape of iid samples to draw.
  Returns:
    iid_sample_fn: Python `callable` taking the same arguments as `sample_fn`
      and returning iid samples. Each returned `Tensor` will have shape
      `concat([sample_shape, shape_of_original_returned_tensor])`.
  """
    sample_shape = distribution_util.expand_to_vector(
        prefer_static.cast(sample_shape, np.int32), tensor_name='sample_shape')
    n = prefer_static.cast(prefer_static.reduce_prod(sample_shape),
                           dtype=np.int32)

    def unflatten(x):
        unflattened_shape = prefer_static.cast(prefer_static.concat(
            [sample_shape, prefer_static.shape(x)[1:]], axis=0),
                                               dtype=np.int32)
        return tf.reshape(x, unflattened_shape)

    def iid_sample_fn(*args, **kwargs):
        """Draws iid samples from `fn`."""

        pfor_loop_body = lambda _: sample_fn(*args, **kwargs)

        seed = kwargs.pop('seed', None)
        try:  # Assume that `seed` is a valid stateful seed (Python `int`).
            kwargs = dict(kwargs, seed=SeedStream(seed, salt='iid_sample')())
            pfor_loop_body = lambda _: sample_fn(*args, **kwargs)
        except TypeError as e:
            # If a stateless seed arg is passed, split it into `n` different stateless
            # seeds, so that we don't just get a bunch of copies of the same sample.
            if TENSOR_SEED_MSG_PREFIX not in str(e):
                raise
            warnings.warn(
                'Saw non-`int` seed {}, implying stateless sampling. '
                'Autovectorized functions that use stateless sampling '
                'may be quite slow because the current implementation '
                'falls back to an explicit loop. This will be fixed in the '
                'future. For now, you will likely see better performance '
                'from stateful sampling, which you can invoke by passing a'
                'traditional Python `int` seed.'.format(seed))
            seed = samplers.split_seed(seed, n=n, salt='iid_sample_stateless')
            pfor_loop_body = (
                lambda i: sample_fn(*args, seed=tf.gather(seed, i), **kwargs))

        draws = parallel_for.pfor(pfor_loop_body, n)
        return tf.nest.map_structure(unflatten, draws, expand_composites=True)

    return iid_sample_fn
Exemple #25
0
  def _expand_sample_shape_to_vector(self, x, name):
    """Helper to `sample` which ensures input is 1D."""
    x_static_val = tf.contrib.util.constant_value(x)
    if x_static_val is None:
      prod = tf.reduce_prod(x)
    else:
      prod = np.prod(x_static_val, dtype=x.dtype.as_numpy_dtype())

    x = util.expand_to_vector(x, tensor_name=name)
    return x, prod
Exemple #26
0
def _asvi_surrogate_for_sample(dist,
                               build_nested_surrogate,
                               sample_shape=None):
    """Builds the surrogate for a `tfd.Sample`-wrapped distribution."""
    dist_sample_shape = distribution_util.expand_to_vector(dist.sample_shape)
    nested_surrogate = yield from build_nested_surrogate(
        dist=dist.distribution,
        sample_shape=(dist_sample_shape if sample_shape is None else ps.concat(
            [sample_shape, dist_sample_shape], axis=0)))
    return independent.Independent(
        nested_surrogate,
        reinterpreted_batch_ndims=ps.rank_from_shape(dist_sample_shape))
Exemple #27
0
    def __init__(self,
                 shape,
                 dtype=None,
                 activation=None,
                 initializer='zeros',
                 regularizer=None,
                 constraint=None,
                 **kwargs):
        """Creates the `VariableLayer`.

    Arguments:
      shape: integer or integer vector specifying the shape of the output of
        this layer.
      dtype: TensorFlow `dtype` of the variable created by this layer.
        Default value: `None` (i.e., `tf.as_dtype(tf.keras.backend.floatx())`).
      activation: Activation function to use.  If you don't specify anything, no
        activation is applied (ie. "linear" activation: `a(x) = x`).
        Default value: `None`.
      initializer: Initializer for the `constant` vector. For example, to
        initialize a trainable (initially standard) `Normal` with
        `tf.math.softplus` transformed scale, one might use:
        ```python
        tfp.layers.BlockwiseInitializer([
            'zeros',
            tf.keras.initializers.Constant(np.log(np.expm1(1.))),  # = 0.541325
        ], sizes=[1, 1])
        ```
        Default value: `'zeros'`.
      regularizer: Regularizer function applied to the `constant` vector.
        Default value: `None`.
      constraint: Constraint function applied to the `constant` vector.
        Default value: `None`.
      **kwargs: Extra arguments forwarded to `tf.keras.layers.Layer`.
    """
        super(VariableLayer, self).__init__(**kwargs)

        self.activation = tf.keras.activations.get(activation)
        self.initializer = tf.keras.initializers.get(initializer)
        self.regularizer = tf.keras.regularizers.get(regularizer)
        self.constraint = tf.keras.constraints.get(constraint)

        shape = tf.get_static_value(dist_util.expand_to_vector(shape))
        if shape is None:
            raise ValueError('Shape must be known statically.')

        self._var = self.add_weight('constant',
                                    shape=shape,
                                    initializer=self.initializer,
                                    regularizer=self.regularizer,
                                    constraint=self.constraint,
                                    dtype=dtype,
                                    trainable=kwargs.get('trainable', True))
Exemple #28
0
  def sample(self, sample_shape=(), seed=None, name=None):
    with tf.name_scope(name or 'sample_particles'):
      sample_shape = prefer_static.concat([
          [self.num_particles],
          dist_util.expand_to_vector(sample_shape)], axis=0)
      x = self.distribution.sample(sample_shape, seed=seed)

      def move_particles_to_rightmost_batch_dim(x, event_shape):
        ndims = prefer_static.rank_from_shape(prefer_static.shape(x))
        event_ndims = prefer_static.rank_from_shape(event_shape)
        return dist_util.move_dimension(x, 0, ndims - event_ndims - 1)
      return tf.nest.map_structure(
          move_particles_to_rightmost_batch_dim,
          x, self.distribution.event_shape_tensor())
Exemple #29
0
 def new(params,
         event_shape=(),
         mean_activation=tf.nn.softplus,
         disp_activation=softplus1,
         validate_args=False,
         name="ZINegativeBinomialDispLayer",
         disp=None,
         rate=None):
     r"""Create the distribution instance from a `params` vector."""
     params = tf.convert_to_tensor(value=params, name='params')
     event_shape = dist_util.expand_to_vector(
         tf.convert_to_tensor(value=event_shape,
                              name='event_shape',
                              dtype=tf.int32),
         tensor_name='event_shape',
     )
     output_shape = tf.concat((tf.shape(input=params)[:-1], event_shape),
                              axis=0)
     ### splitting the parameters
     if disp is None:  # full dispersion
         if rate is None:
             loc, disp, rate = tf.split(params, 3, axis=-1)
             rate = tf.reshape(rate, output_shape)
         else:
             loc, disp = tf.split(params, 2, axis=-1)
         disp = tf.reshape(disp, output_shape)
     else:  # share dispersion
         if rate is None:
             loc, rate = tf.split(params, 2, axis=-1)
             rate = tf.reshape(rate, output_shape)
         else:
             loc = params
     # as count value, do exp if necessary
     loc = tf.reshape(loc, output_shape)
     loc = mean_activation(loc)
     disp = disp_activation(disp)
     # create the distribution
     nb = NegativeBinomialDisp(loc=loc,
                               disp=disp,
                               validate_args=validate_args)
     zinb = ZeroInflated(count_distribution=nb,
                         logits=rate,
                         validate_args=validate_args)
     return tfd.Independent(
         zinb,
         reinterpreted_batch_ndims=tf.size(input=event_shape),
         name=name)
Exemple #30
0
 def new(params, event_shape=(), validate_args=False, name=None):
     """Create the distribution instance from a `params` vector."""
     with tf.name_scope(name, 'IndependentPoisson', [params, event_shape]):
         params = tf.convert_to_tensor(params, name='params')
         event_shape = dist_util.expand_to_vector(tf.convert_to_tensor(
             event_shape, name='event_shape', preferred_dtype=tf.int32),
                                                  tensor_name='event_shape')
         output_shape = tf.concat([
             tf.shape(params)[:-1],
             event_shape,
         ],
                                  axis=0)
         return tfd.Independent(
             tfd.Poisson(log_rate=tf.reshape(params, output_shape),
                         validate_args=validate_args),
             reinterpreted_batch_ndims=tf.size(event_shape),
             validate_args=validate_args)
Exemple #31
0
    def __init__(
        self,
        distribution: tfd.Distribution,
        batch_stack=Union[int, Tuple[int, ...], tf.Tensor],
        validate_args: bool = False,
        name: Optional[str] = None,
    ):
        r"""
        Construct the `BatchStacker` distribution.

        Parameters
        ----------
        distribution : tfd.Distribution
            The base distribution instance to transform. Typically an instance of
            ``tensorflow_probability.distributions.Distribution``.
        batch_stack : Union[int, Tuple[int, ...], tf.Tensor]
            Shape of the stack of distributions. To be more precise, ``distribution`` has
            its underlying ``batch_shape``, what ``batch_stack`` does effectively is to
            add independent replications of ``distribution`` as extra ``batch_shape`` axes,
            to the left of the original ``batch_shape``. The resulting batch shape is
            ``tf.TensorShape(batch_stack) + distribution.batch_shape``.
        validate_args : bool
            Whether to validate input with asserts. If ``validate_args`` is ``False``,
            and the inputs are invalid, correct behavior is not guaranteed.
        name : Optional[str]
            The name for ops managed by the distribution. If ``None``, defaults to
            ``"BatchStacker" + distribution.name``.
        """
        parameters = dict(locals())
        name = name or "BatchStacker" + distribution.name
        self._distribution = distribution
        with tf.name_scope(name) as name:
            batch_stack = distribution_util.expand_to_vector(
                tf.convert_to_tensor(batch_stack,
                                     dtype_hint=tf.int32,
                                     name="batch_stack"))
            self._batch_stack = batch_stack
            super(BatchStacker, self).__init__(
                dtype=self._distribution.dtype,
                reparameterization_type=self._distribution.
                reparameterization_type,
                validate_args=validate_args,
                allow_nan_stats=self._distribution.allow_nan_stats,
                parameters=parameters,
                name=name,
            )
Exemple #32
0
 def new(params,
         event_shape=(),
         count_activation=tf.exp,
         validate_args=False,
         name="ZINegativeBinomialLayer",
         disp=None,
         rate=None):
     r"""Create the distribution instance from a `params` vector."""
     params = tf.convert_to_tensor(value=params, name='params')
     event_shape = dist_util.expand_to_vector(
         tf.convert_to_tensor(value=event_shape,
                              name='event_shape',
                              dtype=tf.int32),
         tensor_name='event_shape',
     )
     output_shape = tf.concat((tf.shape(input=params)[:-1], event_shape),
                              axis=0)
     if disp is None:  # full dispersion
         if rate is None:
             total_count, logits, rate = tf.split(params, 3, axis=-1)
             rate = tf.reshape(rate, output_shape)
         else:
             total_count, logits = tf.split(params, 2, axis=-1)
         logits = tf.reshape(logits, output_shape)
     else:  # share dispersion
         if rate is None:
             total_count, rate = tf.split(params, 2, axis=-1)
             rate = tf.reshape(rate, output_shape)
         else:
             total_count = params
         logits = disp
     total_count = tf.reshape(total_count, output_shape)
     total_count = count_activation(total_count)
     nb = tfd.NegativeBinomial(total_count=total_count,
                               logits=logits,
                               validate_args=validate_args)
     zinb = ZeroInflated(count_distribution=nb,
                         logits=rate,
                         validate_args=validate_args)
     return tfd.Independent(
         zinb,
         reinterpreted_batch_ndims=tf.size(input=event_shape),
         name=name)
Exemple #33
0
 def new(params, event_shape=(), validate_args=False, name=None):
   """Create the distribution instance from a `params` vector."""
   with tf.compat.v1.name_scope(name, 'Gamma',
                                [params, event_shape]):
     params = tf.convert_to_tensor(value=params, name='params')
     event_shape = dist_util.expand_to_vector(
         tf.convert_to_tensor(
             value=event_shape, name='event_shape', dtype=tf.int32),
         tensor_name='event_shape')
     output_shape = tf.concat([
         tf.shape(input=params)[:-1],
         event_shape,
     ], axis=0)
     concentration_params, rate_params = tf.split(params, 2, axis=-1)
     return tfd.Independent(
         tfd.Gamma(
             concentration=tf.reshape(concentration_params, output_shape),
             rate=tf.reshape(rate_params, output_shape),
             validate_args=validate_args),
         reinterpreted_batch_ndims=tf.size(input=event_shape),
         validate_args=validate_args)
Exemple #34
0
 def new(params, event_shape=(), softplus_scale=True,
         validate_args=False, name=None):
   """Create the distribution instance from a `params` vector."""
   with tf.compat.v1.name_scope(name, 'Normal',
                                [params, event_shape]):
     params = tf.convert_to_tensor(value=params, name='params')
     event_shape = dist_util.expand_to_vector(
         tf.convert_to_tensor(
             value=event_shape, name='event_shape', dtype=tf.int32),
         tensor_name='event_shape')
     output_shape = tf.concat([
         tf.shape(input=params)[:-1],
         event_shape,
     ], axis=0)
     loc_params, scale_params = tf.split(params, 2, axis=-1)
     if softplus_scale:
       scale_params = tf.math.softplus(scale_params) + tfd.softplus_inverse(1.0)
     return tfd.Independent(
         tfd.Normal(
             loc=tf.reshape(loc_params, output_shape),
             scale=tf.reshape(scale_params, output_shape),
             validate_args=validate_args),
         reinterpreted_batch_ndims=tf.size(input=event_shape),
         validate_args=validate_args)