Search code examples
python-3.xtensorflowtensorflow-probability

Question on Using SoftmaxCentered Bijector


I am playing with SofmaxCenter bijector in tensorflow_probability and get some errors. Since the document for it is at the infancy state, I was not able to figure out what is wrong. I hope you can help me out.

Basically, given that X is a log-normal random vector of three components, I would like to create another random vector Y which is defined as the softmax-center transformation of X.

The following snippet of code does not give any error

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import functools

import matplotlib.pyplot as plt; plt.style.use('ggplot')
%matplotlib inline

import numpy as np
import seaborn as sns; sns.set_context('notebook')

import tensorflow as tf
import tensorflow_probability as tfp

tfd = tfp.distributions
tfb = tfp.bijectors

tfe = tf.contrib.eager
tfe.enable_eager_execution()

X = tfd.LogNormal(loc=[[-5.0, 0.0, 4.0]], 
                  scale=[[2.0, 1.0, 1.5]])
Y = tfd.TransformedDistribution(
    distribution=X, 
    bijector=tfb.SoftmaxCentered()
)

However, when I try,

Y.sample(10)

I got the following errors,

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-20-9ed8f482f3c1> in <module>
----> 1 Y.sample(10)

anaconda3/lib/python3.6/site-packages/tensorflow_probability/python/distributions/distribution.py in sample(self, sample_shape, seed, name)
    684       samples: a `Tensor` with prepended dimensions `sample_shape`.
    685     """
--> 686     return self._call_sample_n(sample_shape, seed, name)
    687 
    688   def _log_prob(self, value):

anaconda3/lib/python3.6/site-packages/tensorflow_probability/python/distributions/transformed_distribution.py in _call_sample_n(self, sample_shape, seed, name, **kwargs)
    405       # returned result.
    406       y = self.bijector.forward(x, **kwargs)
--> 407       y = self._set_sample_static_shape(y, sample_shape)
    408 
    409       return y

anaconda3/lib/python3.6/site-packages/tensorflow_probability/python/distributions/distribution.py in _set_sample_static_shape(self, x, sample_shape)
   1201     sample_ndims = sample_shape.ndims
   1202     batch_ndims = self.batch_shape.ndims
-> 1203     event_ndims = self.event_shape.ndims
   1204 
   1205     # Infer rank(x).

anaconda3/lib/python3.6/site-packages/tensorflow_probability/python/distributions/distribution.py in event_shape(self)
    622       event_shape: `TensorShape`, possibly unknown.
    623     """
--> 624     return tf.TensorShape(self._event_shape())
    625 
    626   def is_scalar_event(self, name="is_scalar_event"):

anaconda3/lib/python3.6/site-packages/tensorflow_probability/python/distributions/transformed_distribution.py in _event_shape(self)
    345         static_override
    346         if self._is_maybe_event_override
--> 347         else self.distribution.event_shape)
    348 
    349   def _batch_shape_tensor(self):

anaconda3/lib/python3.6/site-packages/tensorflow_probability/python/bijectors/bijector.py in forward_event_shape(self, input_shape)
    680         after applying `forward`. Possibly unknown.
    681     """
--> 682     return self._forward_event_shape(tf.TensorShape(input_shape))
    683 
    684   def _inverse_event_shape_tensor(self, output_shape):

anaconda3/lib/python3.6/site-packages/tensorflow_probability/python/bijectors/softmax_centered.py in _forward_event_shape(self, input_shape)
     68 
     69   def _forward_event_shape(self, input_shape):
---> 70     if input_shape.ndims is None or input_shape[-1] is None:
     71       return input_shape
     72     return tf.TensorShape([input_shape[-1] + 1])

anaconda3/lib/python3.6/site-packages/tensorflow/python/framework/tensor_shape.py in __getitem__(self, key)
    614         return TensorShape(self._dims[key])
    615       else:
--> 616         return self._dims[key]
    617     else:
    618       if isinstance(key, slice):

IndexError: list index out of range

Thank you!


Solution

  • SoftmaxCentered wants to operate on a vector event shape, but the LogNormal distribution has a scalar event shape. If you want to take a softmax across a vector of independent LogNormals, you could do:

    from __future__ import absolute_import
    from __future__ import division
    from __future__ import print_function
    
    import functools
    
    import matplotlib.pyplot as plt; plt.style.use('ggplot')
    %matplotlib inline
    
    import numpy as np
    import seaborn as sns; sns.set_context('notebook')
    
    import tensorflow as tf
    import tensorflow_probability as tfp
    
    tfd = tfp.distributions
    tfb = tfp.bijectors
    
    tfe = tf.contrib.eager
    tfe.enable_eager_execution()
    
    X = tfd.LogNormal(loc=[[-5.0, 0.0, 4.0]], 
                      scale=[[2.0, 1.0, 1.5]])
    Z = tfd.Independent(X, reinterpreted_batch_ndims=1)
    Y = tfd.TransformedDistribution(
        distribution=Z, 
        bijector=tfb.SoftmaxCentered()
    )
    Y.sample(2)
    

    Note, of course, that SoftmaxCentered takes a 3-D space and projects it onto a 3-D manifold in 4-D space. This is to provide invertibility.