tensorflow / tensorflow/probability

Struggles with Gaussian Mixture Models in jax port of tensorflow_distributions

Open
#1,730 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Jupyter Notebook
Stars
4.4k
Forks
1.1k
PR merge metrics
No merged PRs in 30d

Description

I am getting the strangest bugs when trying to make a Guassian mixture model class in the jax substrate of tfd, has anyone experienced this before or know what the correct course of action is? Basically, I either get an annoying error message and the right length of a sample, or no error message but the wrong length of a sample.

When I try this code

from tensorflow_probability.substrates import jax as tfp
tfd = tfp.distributions
class GMM(tfd.MixtureSameFamily):
  def __init__(self, locs, log_scales, log_weights):
    self.locs = locs
    self.log_scales = log_scales
    self.log_weights = log_weights
    mixture_dist = tfd.Categorical(logits=log_weights)
    component_dist = tfd.Normal(loc=locs, scale=jnp.exp(log_scales))
    super().__init__(mixture_dist, component_dist)

gmm = GMM(jnp.array([0.,1.]), jnp.array([0.,1.]), jnp.array([0.,0.]))
gmm.sample( sample_shape=(), seed=jr.PRNGKey(0))

I get this error message
WARNING:root:
Distribution subclass GMM inherits _parameter_properties from its parent (MixtureSameFamily) while also redefining init. The inherited annotations cover the following parameters: dict_keys(['mixture_distribution', 'components_distribution']). It is likely that these do not match the subclass parameters. This may lead to errors when computing batch shapes, slicing into batch dimensions, calling .copy(), flattening the distribution as a CompositeTensor (e.g., when it is passed or returned from a tf.function), and possibly other cases. The recommended pattern for distribution subclasses is to define a new _parameter_propertiesmethod with the subclass parameters, and to store the corresponding parameter values asself._parametersininit`, after
calling the superclass constructor:

class MySubclass(tfd.SomeDistribution):

  def __init__(self, param_a, param_b):
    parameters = dict(locals())
    # ... do subclass initialization ...
    super(MySubclass, self).__init__(**base_class_params)
    # Ensure that the subclass (not base class) parameters are stored.
    self._parameters = parameters

  def _parameter_properties(self, dtype, num_classes=None):
    return dict(
      # Annotations may optionally specify properties, such as `event_ndims`,
      # `default_constraining_bijector_fn`, `specifies_shape`, etc.; see
      # the `ParameterProperties` documentation for details.
      param_a=tfp.util.ParameterProperties(),
      param_b=tfp.util.ParameterProperties())

WARNING:root:
Distribution subclass GMM inherits _parameter_properties from its parent (MixtureSameFamily) while also redefining init. The inherited annotations cover the following parameters: dict_keys(['mixture_distribution', 'components_distribution']). It is likely that these do not match the subclass parameters. This may lead to errors when computing batch shapes, slicing into batch dimensions, calling .copy(), flattening the distribution as a CompositeTensor (e.g., when it is passed or returned from a tf.function), and possibly other cases. The recommended pattern for distribution subclasses is to define a new _parameter_propertiesmethod with the subclass parameters, and to store the corresponding parameter values asself._parametersininit`, after
calling the superclass constructor:

class MySubclass(tfd.SomeDistribution):

  def __init__(self, param_a, param_b):
    parameters = dict(locals())
    # ... do subclass initialization ...
    super(MySubclass, self).__init__(**base_class_params)
    # Ensure that the subclass (not base class) parameters are stored.
    self._parameters = parameters

  def _parameter_properties(self, dtype, num_classes=None):
    return dict(
      # Annotations may optionally specify properties, such as `event_ndims`,
      # `default_constraining_bijector_fn`, `specifies_shape`, etc.; see
      # the `ParameterProperties` documentation for details.
      param_a=tfp.util.ParameterProperties(),
      param_b=tfp.util.ParameterProperties())

Array(1.0883901, dtype=float32)
but at least only one scalar gets sampled.

When I then try to follow the recommendations of the error message with this code

class GMM(tfd.MixtureSameFamily):
  def __init__(self, locs, log_scales, log_weights):
    parameters = dict(locals())
    self.locs = locs
    self.log_scales = log_scales
    self.log_weights = log_weights
    mixture_dist = tfd.Categorical(logits=log_weights)
    component_dist = tfd.Normal(loc=locs, scale=jnp.exp(log_scales))
    super().__init__(mixture_dist, component_dist)
    self._parameters = parameters

  def _parameter_properties(self, dtype=jnp.float32, num_classes=None):
    return dict(
      locs=tfp.util.ParameterProperties(),
      log_scales=tfp.util.ParameterProperties(),
      log_weights=tfp.util.ParameterProperties())
gmm = GMM(jnp.array([0.,1.]), jnp.array([0.,1.]), jnp.array([0.,0.]))
gmm.sample( sample_shape=(), seed=jr.PRNGKey(0))

The error message disappears, but now I get a sample from the two different mixtures, which is not what I want! Array([ 1.85066 , -2.4407113], dtype=float32)

It seems related to these issues:

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the reported GMM examples using the JAX substrate and compare the sample shapes and warnings. Read the MixtureSameFamily behavior and the linked tensorflow/agents#658 and tensorflow/probability#1458 discussions; done means the expected sample shape and mixture semantics are established or a reproducible defect is isolated.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
machine-learning
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.